@ynck/rendux 0.92.1 → 0.93.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -6
- package/EULA-COMMERCIAL.md +1 -1
- package/README.md +551 -101
- package/dist/rendux.cjs.min.js +2 -2
- package/dist/rendux.min.js +2 -2
- package/package.json +1 -9
- package/dist/plugin/i18n.cjs.min.js +0 -2
- package/dist/plugin/i18n.min.js +0 -2
- package/dist/plugin/x-logger.cjs.min.js +0 -2
- package/dist/plugin/x-logger.min.js +0 -2
- package/dist/plugin/x-tooltip.cjs.min.js +0 -2
- package/dist/plugin/x-tooltip.min.js +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,19 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v0.93.3
|
|
4
|
+
|
|
5
|
+
- fixed nested x-for rendering
|
|
6
|
+
|
|
7
|
+
## v0.93.1
|
|
8
|
+
|
|
9
|
+
- x-key diffing algorithm is now reusing DOM nodes thus greatly optimzing rendering (up to 50% faster!)
|
|
10
|
+
|
|
11
|
+
## v0.93.0
|
|
12
|
+
|
|
13
|
+
- remove plugins, focusing on core library
|
|
14
|
+
- Fixed state and rendering target coupling, now state and rendering target element are completely decoupled. The function requires both state and target now : rendux(state, element)
|
|
15
|
+
|
|
16
|
+
## v0.92.0
|
|
2
17
|
|
|
3
|
-
### v0.92
|
|
4
18
|
- Mini Evaluator is now directly embeded in `rendux`
|
|
5
19
|
|
|
6
|
-
|
|
20
|
+
## v0.91.0
|
|
21
|
+
|
|
7
22
|
- Added conditional logging system for plugins and core features
|
|
8
23
|
- Removed x-click-outside plugin
|
|
9
24
|
- Fixed plugin attribute handling and re-rendering
|
|
10
25
|
- Improved plugin logging control via `logs` attribute
|
|
11
26
|
|
|
12
|
-
|
|
27
|
+
## v0.86.0
|
|
28
|
+
|
|
13
29
|
- Inlined plugin core into `rendux.js`, removing dependence on external raw-render-core.js.
|
|
14
30
|
- Added chainable plugin API: `.use()`, `.process()`, `plugins`, and `parsePluginCall` directly on `rendux`.
|
|
15
31
|
- Fixed plugin attribute lookup to avoid invalid CSS selector issues for `render.plugin`.
|
|
16
32
|
|
|
17
|
-
|
|
33
|
+
## v0.84.0
|
|
34
|
+
|
|
18
35
|
- Hidden elements (`x-if`) now reside in an in-memory `DocumentFragment` instead of a `<template>`, preventing hidden nodes from cluttering the DOM or shadow DOM.
|
|
19
|
-
- `<template x-for>` loops are now tracked from both the live DOM and the hidden fragment for correct re-rendering.
|
|
36
|
+
- `<template x-for>` loops are now tracked from both the live DOM and the hidden fragment for correct re-rendering.
|
package/EULA-COMMERCIAL.md
CHANGED
|
@@ -29,4 +29,4 @@ This Commercial EULA ("Agreement") is a legal contract between you ("Licensee")
|
|
|
29
29
|
8. Entire Agreement.
|
|
30
30
|
This Agreement constitutes the entire agreement between the parties and supersedes all prior or contemporaneous agreements.
|
|
31
31
|
|
|
32
|
-
For inquiries or to purchase a commercial license, contact: ynck.chrl@
|
|
32
|
+
For inquiries or to purchase a commercial license, contact: ynck.chrl@protonmail.com
|
package/README.md
CHANGED
|
@@ -1,23 +1,139 @@
|
|
|
1
|
-
.
|
|
4
|
-
Commercial licenses via EULA (See EULA-COMMERCIAL.md for commercial use).
|
|
5
|
-
|
|
1
|
+

|
|
6
2
|
|
|
7
3
|
# rendux
|
|
8
4
|
|
|
9
5
|
## Introduction
|
|
10
6
|
|
|
11
|
-
`rendux` is a lightweight dependency-free templating engine designed for use within Custom Elements (Web Components). It provides reactive templating features through directives, making it easy to create dynamic, state-driven components without a full framework.
|
|
7
|
+
`rendux` is a lightweight dependency-free templating engine designed for use within Custom Elements (Web Components) and plain HTML. It provides reactive templating features through directives, making it easy to create dynamic, state-driven components without a full framework.
|
|
12
8
|
|
|
13
9
|
### Size
|
|
14
10
|
|
|
15
|
-
- Minified: 13.
|
|
16
|
-
- Gzipped: 4.7 KB
|
|
11
|
+
- Minified: 13.2 KB (ESM), 13.3 KB (CJS)
|
|
12
|
+
- Gzipped: ~4.7 KB
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### Via NPM
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @ynck/rendux
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Then import in your project:
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
// ES Module (recommended)
|
|
26
|
+
import { rendux } from '@ynck/rendux';
|
|
27
|
+
|
|
28
|
+
// CommonJS
|
|
29
|
+
const { rendux } = require('@ynck/rendux');
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Via CDN (No Build Step)
|
|
33
|
+
|
|
34
|
+
#### unpkg
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<!-- ES Module -->
|
|
38
|
+
<script type="module">
|
|
39
|
+
import { rendux } from 'https://unpkg.com/@ynck/rendux@latest/dist/rendux.min.js';
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<!-- Or use specific version -->
|
|
43
|
+
<script type="module">
|
|
44
|
+
import { rendux } from 'https://unpkg.com/@ynck/rendux@0.93.3/dist/rendux.min.js';
|
|
45
|
+
</script>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### esm.sh
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<!-- Latest version -->
|
|
52
|
+
<script type="module">
|
|
53
|
+
import { rendux } from 'https://esm.sh/@ynck/rendux@latest'
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<!-- Or with specific version -->
|
|
57
|
+
<script type="module">
|
|
58
|
+
import { rendux } from 'https://esm.sh/@ynck/rendux@0.93.3'
|
|
59
|
+
</script>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Skypack
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<script type="module">
|
|
66
|
+
import { rendux } from 'https://cdn.skypack.dev/@ynck/rendux'
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<!-- Or with specific version -->
|
|
70
|
+
<script type="module">
|
|
71
|
+
import { rendux } from 'https://cdn.skypack.dev/@ynck/rendux@0.93.3';
|
|
72
|
+
</script>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### From Source (Local Development)
|
|
76
|
+
|
|
77
|
+
Clone the repository and use the source directly:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
git clone https://github.com/ynck-chrl/rendux.git
|
|
81
|
+
cd rendux
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then import from source:
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<script type="module">
|
|
88
|
+
import { rendux } from './src/rendux.js';
|
|
89
|
+
</script>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Or if using in a Node.js project:
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
import { rendux } from './path/to/rendux/src/rendux.js';
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Build Outputs
|
|
99
|
+
|
|
100
|
+
When installed via NPM, rendux provides multiple build outputs:
|
|
101
|
+
|
|
102
|
+
- **ESM (ES Modules)**: `dist/rendux.min.js` - For modern browsers and bundlers
|
|
103
|
+
- **CommonJS**: `dist/rendux.cjs.min.js` - For Node.js and legacy tools
|
|
104
|
+
- **Source Maps**: Available for all builds (`.map` files)
|
|
105
|
+
|
|
106
|
+
The `package.json` exports field automatically selects the correct build:
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"exports": {
|
|
111
|
+
".": {
|
|
112
|
+
"import": "./dist/rendux.min.js",
|
|
113
|
+
"require": "./dist/rendux.cjs.min.js"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### TypeScript Support
|
|
120
|
+
|
|
121
|
+
TypeScript definitions are not yet included. You can create a declaration file:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// rendux.d.ts
|
|
125
|
+
declare module 'rendux' {
|
|
126
|
+
export function rendux(state: any, element: HTMLElement): void;
|
|
127
|
+
export function use(plugin: any): typeof rendux;
|
|
128
|
+
// Add other exports as needed
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
|
|
17
133
|
|
|
18
134
|
## Core Concepts
|
|
19
135
|
|
|
20
|
-
`rendux` is
|
|
136
|
+
`rendux` is a function that takes a state object and a DOM element, then processes templating directives within that element. It provides several directives to handle common UI patterns:
|
|
21
137
|
|
|
22
138
|
- `x-if` for conditional rendering
|
|
23
139
|
- `x-for` for list rendering
|
|
@@ -25,7 +141,7 @@ Commercial licenses via EULA (See EULA-COMMERCIAL.md for commercial use).
|
|
|
25
141
|
- `x-*` for dynamic attributes
|
|
26
142
|
- `render` for text content interpolation
|
|
27
143
|
- `@event` for event handling
|
|
28
|
-
- `render.plugin` for plugin execution
|
|
144
|
+
- `render.plugin` for custom plugin execution
|
|
29
145
|
|
|
30
146
|
## Logging System
|
|
31
147
|
|
|
@@ -40,60 +156,79 @@ rendux includes a flexible logging system controlled by the `logs` attribute. Yo
|
|
|
40
156
|
```
|
|
41
157
|
|
|
42
158
|
Available log categories:
|
|
43
|
-
- `plugins`: Plugin execution and results
|
|
44
159
|
- `for`: x-for loop processing
|
|
45
160
|
- `if`: x-if conditional rendering
|
|
46
161
|
- `attr`: x-attr attribute processing
|
|
47
162
|
- `class`: x-class processing
|
|
48
163
|
- `render`: Text content rendering
|
|
164
|
+
- `plugins`: Plugin execution and results
|
|
49
165
|
|
|
50
166
|
## Basic Usage
|
|
51
167
|
|
|
52
168
|
### With Custom Elements (Web Components)
|
|
53
169
|
|
|
54
|
-
#### With Shadow DOM
|
|
170
|
+
#### With Internal State and Shadow DOM
|
|
55
171
|
|
|
56
172
|
```js
|
|
173
|
+
import { rendux } from 'rendux';
|
|
174
|
+
|
|
57
175
|
class MyElement extends HTMLElement {
|
|
58
176
|
constructor() {
|
|
59
177
|
super();
|
|
60
178
|
this.attachShadow({ mode: 'open' });
|
|
179
|
+
|
|
180
|
+
// Internal component state
|
|
181
|
+
this.state = {
|
|
182
|
+
title: 'User List',
|
|
183
|
+
users: [
|
|
184
|
+
{ name: 'Alice', active: true },
|
|
185
|
+
{ name: 'Bob', active: false }
|
|
186
|
+
]
|
|
187
|
+
};
|
|
61
188
|
}
|
|
62
189
|
|
|
63
|
-
// Example component state
|
|
64
|
-
users = [
|
|
65
|
-
{ name: 'Alice', active: true },
|
|
66
|
-
{ name: 'Bob', active: false }
|
|
67
|
-
];
|
|
68
|
-
|
|
69
190
|
connectedCallback() {
|
|
70
191
|
this.shadowRoot.innerHTML = `
|
|
71
192
|
<div>
|
|
72
|
-
<h2 render="title"
|
|
193
|
+
<h2 render="title"></h2>
|
|
73
194
|
<template x-for="user of users">
|
|
74
195
|
<div x-class="(active, user.active)">
|
|
75
196
|
<span render="user.name"></span>
|
|
197
|
+
<button @click="toggleUser(user)">Toggle</button>
|
|
76
198
|
</div>
|
|
77
199
|
</template>
|
|
78
200
|
</div>
|
|
79
201
|
`;
|
|
80
|
-
|
|
202
|
+
// Pass state and element - renders into shadowRoot
|
|
203
|
+
rendux(this.state, this);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
toggleUser(user) {
|
|
207
|
+
user.active = !user.active;
|
|
208
|
+
// Re-render after state change
|
|
209
|
+
rendux(this.state, this);
|
|
81
210
|
}
|
|
82
211
|
}
|
|
83
212
|
```
|
|
84
213
|
|
|
85
|
-
####
|
|
214
|
+
#### With Internal State and Light DOM
|
|
86
215
|
|
|
87
216
|
```js
|
|
88
|
-
import { rendux } from '
|
|
217
|
+
import { rendux } from 'rendux';
|
|
89
218
|
|
|
90
219
|
class MyElement extends HTMLElement {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
220
|
+
constructor() {
|
|
221
|
+
super();
|
|
222
|
+
|
|
223
|
+
// Internal component state
|
|
224
|
+
this.state = {
|
|
225
|
+
title: 'User List',
|
|
226
|
+
users: [
|
|
227
|
+
{ name: 'Alice', active: true },
|
|
228
|
+
{ name: 'Bob', active: false }
|
|
229
|
+
]
|
|
230
|
+
};
|
|
231
|
+
}
|
|
97
232
|
|
|
98
233
|
connectedCallback() {
|
|
99
234
|
// Render directly into light DOM (no shadow root)
|
|
@@ -108,20 +243,60 @@ class MyElement extends HTMLElement {
|
|
|
108
243
|
</template>
|
|
109
244
|
</div>
|
|
110
245
|
`;
|
|
111
|
-
|
|
246
|
+
// Pass state and element - renders into element itself (light DOM)
|
|
247
|
+
rendux(this.state, this);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
toggleUser(user) {
|
|
251
|
+
user.active = !user.active;
|
|
252
|
+
// Re-render after state change
|
|
253
|
+
rendux(this.state, this);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
#### With External/Global State
|
|
259
|
+
|
|
260
|
+
```js
|
|
261
|
+
import { rendux } from 'rendux';
|
|
262
|
+
import { state } from './state.js'; // External state (could be from a store)
|
|
263
|
+
|
|
264
|
+
class MyGlobalUsers extends HTMLElement {
|
|
265
|
+
connectedCallback() {
|
|
266
|
+
this.innerHTML = `
|
|
267
|
+
<div>
|
|
268
|
+
<h2 render="title"></h2>
|
|
269
|
+
<template x-for="(user, userIndex) of users">
|
|
270
|
+
<div x-class="(active, user.active) (non-active, !user.active)">
|
|
271
|
+
<span render="user.name"></span>
|
|
272
|
+
<span render="userIndex"></span>
|
|
273
|
+
<button @click="toggleUser(user)">Toggle</button>
|
|
274
|
+
</div>
|
|
275
|
+
</template>
|
|
276
|
+
</div>
|
|
277
|
+
`;
|
|
278
|
+
// Use external state with this element
|
|
279
|
+
rendux(state, this);
|
|
112
280
|
}
|
|
113
281
|
|
|
114
282
|
toggleUser(user) {
|
|
115
283
|
user.active = !user.active;
|
|
116
|
-
|
|
284
|
+
// Re-render with external state
|
|
285
|
+
rendux(state, this);
|
|
117
286
|
}
|
|
118
287
|
}
|
|
119
288
|
```
|
|
120
289
|
|
|
290
|
+
**Key Points:**
|
|
291
|
+
- **First argument**: Always the state object (can be `this.state`, an external state, or any object/array)
|
|
292
|
+
- **Second argument**: Always the DOM element (`this` in Custom Elements)
|
|
293
|
+
- **Rendering target**: If element has `shadowRoot`, renders into it; otherwise renders into the element itself (light DOM)
|
|
294
|
+
- **Template expressions**: Reference properties directly from the state object (e.g., `title`, `users`, not `state.title`)
|
|
295
|
+
|
|
121
296
|
|
|
122
297
|
### With Plain HTML
|
|
123
298
|
|
|
124
|
-
You can also use rendux with plain HTML
|
|
299
|
+
You can also use rendux with plain HTML:
|
|
125
300
|
|
|
126
301
|
```html
|
|
127
302
|
<!DOCTYPE html>
|
|
@@ -130,32 +305,32 @@ You can also use rendux with plain HTML by creating a context object:
|
|
|
130
305
|
<script type="module">
|
|
131
306
|
import { rendux } from './src/rendux.js';
|
|
132
307
|
|
|
133
|
-
// Create a
|
|
134
|
-
const
|
|
308
|
+
// Create a state object with your data
|
|
309
|
+
const state = {
|
|
135
310
|
title: 'User List',
|
|
136
311
|
users: [
|
|
137
312
|
{ name: 'Alice', active: true },
|
|
138
313
|
{ name: 'Bob', active: false }
|
|
139
|
-
]
|
|
140
|
-
|
|
141
|
-
// Add methods if needed
|
|
142
|
-
toggleUser(user) {
|
|
143
|
-
user.active = !user.active;
|
|
144
|
-
rendux.call(this); // Re-render after state change
|
|
145
|
-
}
|
|
314
|
+
]
|
|
146
315
|
};
|
|
147
316
|
|
|
148
|
-
//
|
|
149
|
-
|
|
317
|
+
// Get the container element
|
|
318
|
+
const container = document.querySelector('#app');
|
|
319
|
+
|
|
320
|
+
// Initial render
|
|
321
|
+
rendux(state, container);
|
|
322
|
+
|
|
323
|
+
// To update after state changes:
|
|
324
|
+
// state.users.push({ name: 'Charlie', active: true });
|
|
325
|
+
// rendux(state, container);
|
|
150
326
|
</script>
|
|
151
327
|
</head>
|
|
152
328
|
<body>
|
|
153
|
-
<div>
|
|
329
|
+
<div id="app">
|
|
154
330
|
<h2 render="title">User List</h2>
|
|
155
331
|
<template x-for="user of users">
|
|
156
332
|
<div x-class="(active, user.active)">
|
|
157
333
|
<span render="user.name"></span>
|
|
158
|
-
<button @click="toggleUser(user)">Toggle</button>
|
|
159
334
|
</div>
|
|
160
335
|
</template>
|
|
161
336
|
</div>
|
|
@@ -164,19 +339,19 @@ You can also use rendux with plain HTML by creating a context object:
|
|
|
164
339
|
```
|
|
165
340
|
|
|
166
341
|
**Key Points for Plain HTML Usage:**
|
|
167
|
-
- Create a
|
|
168
|
-
-
|
|
169
|
-
- Call `rendux
|
|
170
|
-
-
|
|
342
|
+
- Create a state object with your data
|
|
343
|
+
- Pass the state and container element to `rendux(state, element)`
|
|
344
|
+
- Call `rendux(state, element)` again after state changes to re-render
|
|
345
|
+
- Event handlers (like `@click`) can reference methods if you add them to the element's prototype or use inline expressions
|
|
171
346
|
|
|
172
347
|
### With CommonJS (Node.js)
|
|
173
348
|
|
|
174
349
|
```js
|
|
175
350
|
// Import using CommonJS
|
|
176
|
-
const { rendux } = require('
|
|
351
|
+
const { rendux } = require('@ynck/rendux');
|
|
177
352
|
|
|
178
|
-
// Create a
|
|
179
|
-
const
|
|
353
|
+
// Create a state object with your data
|
|
354
|
+
const state = {
|
|
180
355
|
title: 'Server Context',
|
|
181
356
|
users: [
|
|
182
357
|
{ name: 'Alice', active: true },
|
|
@@ -188,7 +363,7 @@ const context = {
|
|
|
188
363
|
// For Node.js, use with a DOM implementation like jsdom
|
|
189
364
|
const { JSDOM } = require('jsdom');
|
|
190
365
|
const dom = new JSDOM(`
|
|
191
|
-
<div>
|
|
366
|
+
<div id="app">
|
|
192
367
|
<h2 render="title">User List</h2>
|
|
193
368
|
<template x-for="user of users">
|
|
194
369
|
<div x-class="(active, user.active)">
|
|
@@ -201,8 +376,11 @@ const dom = new JSDOM(`
|
|
|
201
376
|
// Set up global document for rendux
|
|
202
377
|
global.document = dom.window.document;
|
|
203
378
|
|
|
204
|
-
//
|
|
205
|
-
|
|
379
|
+
// Get the container element
|
|
380
|
+
const container = dom.window.document.querySelector('#app');
|
|
381
|
+
|
|
382
|
+
// Call rendux with state and element
|
|
383
|
+
rendux(state, container);
|
|
206
384
|
```
|
|
207
385
|
|
|
208
386
|
**When to Use `rendux.cjs`:**
|
|
@@ -219,7 +397,58 @@ Use the CommonJS build (`dist/rendux.cjs`) in these scenarios:
|
|
|
219
397
|
|
|
220
398
|
For modern projects with native ESM support, prefer the ESM build (`dist/rendux.js`) instead.
|
|
221
399
|
|
|
400
|
+
### With Reactive State Libraries
|
|
401
|
+
|
|
402
|
+
rendux works seamlessly with reactive state management libraries. Here's an example using a Proxy-based reactive state:
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
import { rendux } from 'rendux';
|
|
406
|
+
import { restate } from 'restate'; // Or any reactive state library
|
|
407
|
+
|
|
408
|
+
// Create reactive state
|
|
409
|
+
const state = restate({
|
|
410
|
+
title: 'User List',
|
|
411
|
+
users: [
|
|
412
|
+
{ name: 'Alice', active: true },
|
|
413
|
+
{ name: 'Bob', active: false }
|
|
414
|
+
]
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
class MyComponent extends HTMLElement {
|
|
418
|
+
connectedCallback() {
|
|
419
|
+
this.innerHTML = `
|
|
420
|
+
<div>
|
|
421
|
+
<h2 render="title"></h2>
|
|
422
|
+
<template x-for="user of users">
|
|
423
|
+
<div x-class="(active, user.active)">
|
|
424
|
+
<span render="user.name"></span>
|
|
425
|
+
<button @click="toggleUser(user)">Toggle</button>
|
|
426
|
+
</div>
|
|
427
|
+
</template>
|
|
428
|
+
</div>
|
|
429
|
+
`;
|
|
430
|
+
|
|
431
|
+
// Initial render
|
|
432
|
+
rendux(state, this);
|
|
433
|
+
|
|
434
|
+
// Set up automatic re-rendering on state changes
|
|
435
|
+
state.$onChange(() => {
|
|
436
|
+
rendux(state, this);
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
toggleUser(user) {
|
|
441
|
+
// Just mutate - reactive state will trigger re-render
|
|
442
|
+
user.active = !user.active;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
```
|
|
222
446
|
|
|
447
|
+
**Benefits of Reactive State:**
|
|
448
|
+
- Automatic re-rendering when state changes
|
|
449
|
+
- No need to manually call `rendux()` after every update
|
|
450
|
+
- Works with any Proxy-based reactive library
|
|
451
|
+
- rendux handles circular references and deep objects safely
|
|
223
452
|
|
|
224
453
|
## Directives
|
|
225
454
|
|
|
@@ -318,70 +547,182 @@ The event object is automatically available in handlers as `event`.
|
|
|
318
547
|
|
|
319
548
|
## Plugin System
|
|
320
549
|
|
|
321
|
-
rendux includes
|
|
550
|
+
rendux includes a powerful plugin system that allows you to extend templating functionality with custom directives.
|
|
322
551
|
|
|
323
552
|
### Using Plugins
|
|
324
553
|
|
|
554
|
+
Plugins are registered using the `use()` method, which is chainable:
|
|
555
|
+
|
|
325
556
|
```js
|
|
326
|
-
import { rendux } from '
|
|
327
|
-
import {
|
|
328
|
-
|
|
557
|
+
import { rendux } from 'rendux';
|
|
558
|
+
import { myCustomPlugin } from './plugins/my-plugin.js';
|
|
559
|
+
|
|
560
|
+
// Register plugin (chainable)
|
|
561
|
+
rendux.use(myCustomPlugin);
|
|
329
562
|
|
|
330
|
-
//
|
|
563
|
+
// Or chain multiple plugins
|
|
331
564
|
rendux
|
|
332
|
-
.use(
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
fr: { greeting: 'Bonjour!' }
|
|
336
|
-
}
|
|
337
|
-
}))
|
|
338
|
-
.use(xTooltip);
|
|
565
|
+
.use(plugin1)
|
|
566
|
+
.use(plugin2)
|
|
567
|
+
.use(plugin3);
|
|
339
568
|
```
|
|
340
569
|
|
|
341
|
-
### Using Plugin Directives
|
|
570
|
+
### Using Plugin Directives in Templates
|
|
571
|
+
|
|
572
|
+
Once registered, plugins can be used with the `render.pluginName` attribute:
|
|
342
573
|
|
|
343
574
|
```html
|
|
344
|
-
<!--
|
|
575
|
+
<!-- Using a custom formatter plugin -->
|
|
576
|
+
<span render.format="user.name">Default Name</span>
|
|
577
|
+
|
|
578
|
+
<!-- Using a custom i18n plugin -->
|
|
345
579
|
<p render.i18n="greeting">Hello!</p>
|
|
346
580
|
|
|
347
|
-
<!--
|
|
348
|
-
<
|
|
581
|
+
<!-- Generic plugin syntax -->
|
|
582
|
+
<span render.plugin="myPlugin('arg1', 'arg2')">Fallback</span>
|
|
349
583
|
```
|
|
350
584
|
|
|
351
|
-
###
|
|
585
|
+
### Creating Custom Plugins
|
|
352
586
|
|
|
353
|
-
A plugin is an object with
|
|
587
|
+
A plugin is an object with specific properties and methods:
|
|
354
588
|
|
|
355
589
|
```js
|
|
356
590
|
export const myPlugin = {
|
|
357
|
-
// Required
|
|
358
|
-
name: '
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
591
|
+
// Required: Plugin name (used in render.pluginName)
|
|
592
|
+
name: 'myPlugin',
|
|
593
|
+
|
|
594
|
+
// Required: Main execution function
|
|
595
|
+
execute(value, ...args) {
|
|
596
|
+
// Process the value and return result
|
|
597
|
+
// The returned string becomes the element's textContent
|
|
598
|
+
return processedValue;
|
|
363
599
|
},
|
|
364
|
-
|
|
365
|
-
// Optional
|
|
600
|
+
|
|
601
|
+
// Optional: Called once before any plugin executes
|
|
366
602
|
onBeforeRender(root, component) {
|
|
367
|
-
//
|
|
368
|
-
//
|
|
603
|
+
// Initialize plugin state
|
|
604
|
+
// Access to root element and component context
|
|
605
|
+
},
|
|
606
|
+
|
|
607
|
+
// Optional: Called before each element execution
|
|
608
|
+
onBeforeExecute(element, rawValue, context) {
|
|
609
|
+
// Setup for this specific element
|
|
610
|
+
// Can modify element attributes, add classes, etc.
|
|
611
|
+
},
|
|
612
|
+
|
|
613
|
+
// Optional: Called after each element execution
|
|
614
|
+
onAfterExecute(element, rawValue, context) {
|
|
615
|
+
// Cleanup or post-processing for this element
|
|
369
616
|
},
|
|
370
617
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
//
|
|
618
|
+
// Optional: Called once after all plugins execute (can be async)
|
|
619
|
+
async onAfterRender(root, context) {
|
|
620
|
+
// Final cleanup or async operations
|
|
621
|
+
// This is the only lifecycle hook that supports async
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
### Plugin Example: Text Formatter
|
|
627
|
+
|
|
628
|
+
Here's a complete example of a text formatting plugin:
|
|
629
|
+
|
|
630
|
+
```js
|
|
631
|
+
export const formatPlugin = {
|
|
632
|
+
name: 'format',
|
|
633
|
+
|
|
634
|
+
execute(value, format = 'uppercase') {
|
|
635
|
+
if (typeof value !== 'string') {
|
|
636
|
+
value = String(value);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
switch(format) {
|
|
640
|
+
case 'uppercase':
|
|
641
|
+
return value.toUpperCase();
|
|
642
|
+
case 'lowercase':
|
|
643
|
+
return value.toLowerCase();
|
|
644
|
+
case 'capitalize':
|
|
645
|
+
return value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();
|
|
646
|
+
case 'reverse':
|
|
647
|
+
return value.split('').reverse().join('');
|
|
648
|
+
default:
|
|
649
|
+
return value;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
// Register the plugin
|
|
655
|
+
rendux.use(formatPlugin);
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
Usage in template:
|
|
659
|
+
|
|
660
|
+
```html
|
|
661
|
+
<span render.format="user.name, 'capitalize'">John Doe</span>
|
|
662
|
+
<span render.format="title, 'uppercase'">Hello World</span>
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### Plugin Example: Conditional Formatter
|
|
666
|
+
|
|
667
|
+
A more advanced plugin with lifecycle hooks:
|
|
668
|
+
|
|
669
|
+
```js
|
|
670
|
+
export const conditionalPlugin = {
|
|
671
|
+
name: 'showIf',
|
|
672
|
+
|
|
673
|
+
onBeforeRender(root, component) {
|
|
674
|
+
// Store original content for elements using this plugin
|
|
675
|
+
this.originalContent = new WeakMap();
|
|
374
676
|
},
|
|
375
677
|
|
|
376
|
-
|
|
377
|
-
//
|
|
378
|
-
|
|
678
|
+
execute(condition, trueValue, falseValue = '') {
|
|
679
|
+
// Evaluate condition and return appropriate value
|
|
680
|
+
return condition ? trueValue : falseValue;
|
|
379
681
|
},
|
|
380
682
|
|
|
381
|
-
|
|
382
|
-
//
|
|
383
|
-
|
|
384
|
-
|
|
683
|
+
onAfterExecute(element, rawValue, context) {
|
|
684
|
+
// Add a custom class based on the condition
|
|
685
|
+
const condition = rawValue.split(',')[0].trim();
|
|
686
|
+
if (condition) {
|
|
687
|
+
element.classList.add('visible');
|
|
688
|
+
} else {
|
|
689
|
+
element.classList.remove('visible');
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
### Plugin Best Practices
|
|
696
|
+
|
|
697
|
+
1. **Validate Inputs**: Always validate and sanitize plugin inputs
|
|
698
|
+
2. **Handle Errors Gracefully**: Use try-catch to prevent plugin errors from breaking rendering
|
|
699
|
+
3. **Keep Plugins Focused**: Each plugin should do one thing well
|
|
700
|
+
4. **Document Parameters**: Clearly document what arguments your plugin expects
|
|
701
|
+
5. **Return Strings**: The `execute()` method should return a string (or value that converts to string)
|
|
702
|
+
6. **Avoid Side Effects**: Minimize DOM manipulation outside of the element being processed
|
|
703
|
+
|
|
704
|
+
### Security Considerations for Plugins
|
|
705
|
+
|
|
706
|
+
When creating plugins, be mindful of security:
|
|
707
|
+
|
|
708
|
+
```js
|
|
709
|
+
export const safePlugin = {
|
|
710
|
+
name: 'safe',
|
|
711
|
+
|
|
712
|
+
execute(userInput) {
|
|
713
|
+
// Validate input type
|
|
714
|
+
if (typeof userInput !== 'string') {
|
|
715
|
+
return '';
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// Sanitize HTML entities
|
|
719
|
+
return userInput.replace(/[<>&"']/g, char => ({
|
|
720
|
+
'<': '<',
|
|
721
|
+
'>': '>',
|
|
722
|
+
'&': '&',
|
|
723
|
+
'"': '"',
|
|
724
|
+
"'": '''
|
|
725
|
+
})[char]);
|
|
385
726
|
}
|
|
386
727
|
};
|
|
387
728
|
```
|
|
@@ -432,31 +773,140 @@ render="window.location = 'evil.com'" ✗ (window not accessible)
|
|
|
432
773
|
|
|
433
774
|
**Safe Template Processing**
|
|
434
775
|
- Template elements (`<template x-for>`) use `.content` property, not innerHTML
|
|
435
|
-
-
|
|
776
|
+
- Attributes are processed safely without executing embedded scripts
|
|
436
777
|
- Event handlers are properly scoped and don't use string-to-function conversion
|
|
437
778
|
|
|
438
779
|
### Best Practices for Secure Usage
|
|
439
780
|
|
|
440
|
-
1. **Validate
|
|
781
|
+
1. **Validate Inputs**: Always validate and sanitize user inputs before adding them to state
|
|
441
782
|
2. **Context Isolation**: Each component maintains its own isolated context
|
|
442
783
|
3. **No Script Injection**: User data in expressions is evaluated safely, not executed as code
|
|
784
|
+
4. **Safe State Updates**: Mutate state objects directly and call `rendux()` to re-render, avoiding innerHTML manipulation
|
|
443
785
|
|
|
444
786
|
```js
|
|
445
|
-
// Safe
|
|
446
|
-
|
|
787
|
+
// Safe state update example
|
|
788
|
+
class MyComponent extends HTMLElement {
|
|
789
|
+
constructor() {
|
|
790
|
+
super();
|
|
791
|
+
this.state = {
|
|
792
|
+
userInput: ''
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
handleInput(event) {
|
|
797
|
+
// Validate and sanitize
|
|
798
|
+
const value = event.target.value;
|
|
799
|
+
if (typeof value === 'string' && value.length < 100) {
|
|
800
|
+
this.state.userInput = value.trim();
|
|
801
|
+
rendux(this.state, this); // Safe re-render
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
This security model makes rendux suitable for applications handling user-generated content while maintaining the flexibility of a templating engine.
|
|
808
|
+
|
|
809
|
+
### Security Audit Summary
|
|
810
|
+
|
|
811
|
+
rendux has been designed and audited to ensure maximum security for web applications:
|
|
812
|
+
|
|
813
|
+
#### Core Engine Security ✓
|
|
814
|
+
|
|
815
|
+
**No Dangerous Functions**
|
|
816
|
+
- ✓ No `eval()` or `Function()` constructor used
|
|
817
|
+
- ✓ No `innerHTML` for dynamic content
|
|
818
|
+
- ✓ No `outerHTML` manipulation
|
|
819
|
+
- ✓ No `document.write()`
|
|
820
|
+
|
|
821
|
+
**Safe Content Rendering**
|
|
822
|
+
- ✓ All dynamic content uses `textContent` (auto-escapes HTML)
|
|
823
|
+
- ✓ User input like `<script>alert('XSS')</script>` is rendered as escaped text, never executed
|
|
824
|
+
- ✓ Plugin outputs are also rendered via `textContent`
|
|
825
|
+
|
|
826
|
+
**Sandboxed Expression Evaluator**
|
|
827
|
+
- ✓ Custom parser with whitelisted globals only
|
|
828
|
+
- ✓ Allowed: `Math`, `Date`, `Number`, `String`, `Boolean`, `JSON`, `Array`, `parseInt`, `parseFloat`, `isFinite`
|
|
829
|
+
- ✗ Blocked: `window`, `document`, `eval`, `fetch`, `XMLHttpRequest`, `localStorage`, `location`
|
|
830
|
+
|
|
831
|
+
**Safe Template Processing**
|
|
832
|
+
- ✓ Templates use `.content` property (no innerHTML)
|
|
833
|
+
- ✓ Event handlers use sandboxed evaluator (no string-to-function conversion)
|
|
834
|
+
|
|
835
|
+
#### Plugin System Security
|
|
836
|
+
|
|
837
|
+
**Framework Security ✓**
|
|
838
|
+
- ✓ Plugin output automatically escaped via `textContent`
|
|
839
|
+
- ✓ Plugin execution wrapped in try-catch for graceful error handling
|
|
840
|
+
- ✓ Plugins cannot access dangerous globals
|
|
841
|
+
|
|
842
|
+
**Developer Responsibility ⚠️**
|
|
843
|
+
|
|
844
|
+
Plugin developers **must validate and sanitize** all inputs in their `execute()` method:
|
|
845
|
+
|
|
846
|
+
```js
|
|
847
|
+
// ✓ SECURE: Properly validated plugin
|
|
848
|
+
export const securePlugin = {
|
|
447
849
|
name: 'format',
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
850
|
+
|
|
851
|
+
execute(value, options = {}) {
|
|
852
|
+
// 1. Type validation
|
|
853
|
+
if (typeof value !== 'string') {
|
|
854
|
+
console.warn('Invalid input type, expected string');
|
|
855
|
+
return '';
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// 2. Length validation
|
|
859
|
+
if (value.length > 10000) {
|
|
860
|
+
console.warn('Input too long');
|
|
861
|
+
return value.substring(0, 10000);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// 3. Sanitization (if needed for your use case)
|
|
865
|
+
const sanitized = value.replace(/[<>&"']/g, char => ({
|
|
452
866
|
'<': '<', '>': '>', '&': '&',
|
|
453
867
|
'"': '"', "'": '''
|
|
454
868
|
})[char]);
|
|
869
|
+
|
|
870
|
+
// 4. Safe processing
|
|
871
|
+
return sanitized.toUpperCase();
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
// ✗ INSECURE: No validation
|
|
876
|
+
export const insecurePlugin = {
|
|
877
|
+
name: 'unsafe',
|
|
878
|
+
execute(value) {
|
|
879
|
+
// Dangerous: No type checking, no validation
|
|
880
|
+
return value.toUpperCase(); // Crashes if value is not a string
|
|
455
881
|
}
|
|
456
882
|
};
|
|
457
883
|
```
|
|
458
884
|
|
|
459
|
-
|
|
885
|
+
**Plugin Security Checklist**
|
|
886
|
+
|
|
887
|
+
When creating plugins, ensure you:
|
|
888
|
+
|
|
889
|
+
1. ✓ **Validate input types** - Check `typeof` before processing
|
|
890
|
+
2. ✓ **Validate input length** - Prevent resource exhaustion
|
|
891
|
+
3. ✓ **Sanitize if needed** - Escape special characters for your use case
|
|
892
|
+
4. ✓ **Handle errors gracefully** - Use try-catch to prevent crashes
|
|
893
|
+
5. ✓ **Return safe values** - Always return strings or values that convert to string
|
|
894
|
+
6. ✓ **Document requirements** - Clearly document expected input types and formats
|
|
895
|
+
7. ✓ **Avoid DOM manipulation** - Minimize direct DOM changes outside the element
|
|
896
|
+
8. ✓ **Test with malicious input** - Test with XSS payloads, large inputs, invalid types
|
|
897
|
+
|
|
898
|
+
#### Security Guarantees
|
|
899
|
+
|
|
900
|
+
| Feature | Core Engine | Plugin System |
|
|
901
|
+
|---------|-------------|---------------|
|
|
902
|
+
| XSS Prevention | ✓ Guaranteed | ✓ Framework protected, ⚠️ validate inputs |
|
|
903
|
+
| Code Injection | ✓ Blocked | ✓ Blocked |
|
|
904
|
+
| HTML Escaping | ✓ Automatic | ✓ Automatic |
|
|
905
|
+
| Global Access | ✓ Whitelisted only | ✓ Whitelisted only |
|
|
906
|
+
| Expression Safety | ✓ Sandboxed | ✓ Sandboxed |
|
|
907
|
+
| Input Validation | ✓ Type-checked | ⚠️ Developer responsibility |
|
|
908
|
+
|
|
909
|
+
**Verdict**: rendux provides a **secure foundation** for web applications. The core engine is hardened against XSS and code injection attacks. Plugin developers must follow security best practices and validate all inputs to maintain the security guarantee.
|
|
460
910
|
|
|
461
911
|
## License
|
|
462
912
|
|
package/dist/rendux.cjs.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! rendux v0.
|
|
2
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e={Math:Math,Date:Date,Number:Number,String:String,Boolean:Boolean,JSON:JSON,parseInt:parseInt,parseFloat:parseFloat,isFinite:isFinite,Array:Array};function t(t,r={}){const n=function(e){const t=[];let r=0;for(;r<e.length;){let n=e[r];if(/\s/.test(n)){r++;continue}if('"'===n||"'"===n){const o=n;let s="";for(r++;r<e.length&&e[r]!==o;)"\\"===e[r]?(r++,r<e.length&&(s+=e[r++])):s+=e[r++];r++,t.push({type:"string",value:s});continue}if(/[0-9]/.test(n)||"."===n&&/[0-9]/.test(e[r+1])){let n=r;for(;r<e.length&&/[0-9]/.test(e[r]);)r++;if("."===e[r])for(r++;r<e.length&&/[0-9]/.test(e[r]);)r++;const o=parseFloat(e.slice(n,r));t.push({type:"number",value:o});continue}if(/[a-zA-Z_$]/.test(n)){let n=r;for(r++;r<e.length&&/[a-zA-Z0-9_$]/.test(e[r]);)r++;const o=e.slice(n,r);"true"===o||"false"===o?t.push({type:"boolean",value:"true"===o}):"null"===o?t.push({type:"null",value:null}):t.push({type:"identifier",value:o});continue}const o=e.substr(r,2),s=e.substr(r,3);if(["===","!=="].includes(s))t.push({type:"operator",value:s}),r+=3;else if(["==","!=",">=","<=","&&","||"].includes(o))t.push({type:"operator",value:o}),r+=2;else{if(!["+","-","*","/","%",">","<","!","?",":","(",")","[","]",".",","].includes(n))throw new Error(`Invalid character '${n}' in expression`);t.push({type:"operator",value:n}),r++}}return t.push({type:"EOF"}),t}(t);let o=0;function s(){return n[o]||{type:"EOF"}}function a(){return n[o++]||{type:"EOF"}}function i(e,t){const r=s();if(r.type!==e||void 0!==t&&r.value!==t)throw new Error(`Expected ${t||e} but got ${r.value}`);return a(),r}function l(e){const t=s();return"operator"===t.type&&t.value===e}const c=u();if("EOF"!==s().type)throw new Error(`Unexpected token: ${s().value}`);return c;function u(){let e=function(){let e=f();for(;l("||");){a();const t=f();e=e||t}return e}();if(l("?")){a();const t=u();i("operator",":");const r=u();e=e?t:r}return e}function f(){let e=p();for(;l("&&");){a();const t=p();e=e&&t}return e}function p(){let e=d();for(;["==","!=","===","!=="].includes(s().value);){const t=a().value,r=d();switch(t){case"==":e=e==r;break;case"!=":e=e!=r;break;case"===":e=e===r;break;case"!==":e=e!==r}}return e}function d(){let e=h();for(;[">","<",">=","<="].includes(s().value);){const t=a().value,r=h();switch(t){case">":e=e>r;break;case"<":e=e<r;break;case">=":e=e>=r;break;case"<=":e=e<=r}}return e}function h(){let e=x();for(;["+","-"].includes(s().value);){const t=a().value,r=x();e="+"===t?e+r:e-r}return e}function x(){let e=g();for(;["*","/","%"].includes(s().value);){const t=a().value,r=g();switch(t){case"*":e*=r;break;case"/":e/=r;break;case"%":e%=r}}return e}function g(){if(["!","+","-"].includes(s().value)){const e=a().value,t=g();switch(e){case"!":return!t;case"+":return+t;case"-":return-t}}return function(){const t=s();if("number"===t.type||"string"===t.type||"boolean"===t.type||"null"===t.type)return a(),t.value;if("identifier"===t.type){a();let n=function(t){if(t in r)return r[t];if(t in e)return e[t];if(null!=r.this&&t in r.this)return r.this[t];throw new Error(`Unknown identifier: ${t}`)}(t.value);for(;;)if(l(".")){a();const e=i("identifier").value;n=null==n?void 0:n[e]}else if(l("[")){a();const e=u();i("operator","]"),n=null==n?void 0:n[e]}else{if(!l("("))break;{a();const e=[];if(!l(")"))do{e.push(u())}while(l(",")&&a());if(i("operator",")"),"function"!=typeof n)throw new Error(`'${t.value}' is not a function`);n=n.apply(r.this,e)}}return n}if(l("(")){a();const e=u();return i("operator",")"),e}throw new Error(`Unexpected token: ${t.value}`)}()}}const r=new Map;function n(e){if(!e||!e.name)throw new Error("Invalid plugin");r.set(e.name,e)}function o(e,t={}){const n=e.match(/^([a-zA-Z_$][\w$]*)\s*\(\s*(.*)\s*\)$/);if(!n)return null;const o=n[1],s=r.get(o);if(!s)return null;const a=n[2].trim();if(""===a)return{plugin:s,args:[]};return{plugin:s,args:a.split(/\s*,\s*/).map(e=>{if(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);if(/^-?\d+(?:\.\d+)?$/.test(e))return parseFloat(e);if(e in t)return t[e];throw new Error(`Unknown identifier: ${e}`)})}}async function s(e=document,t={}){const n=Array.from(e.querySelectorAll("*")).filter(e=>Array.from(e.attributes).some(e=>e.name.startsWith("render.")));for(const e of n)for(const n of Array.from(e.attributes)){if(!n.name.startsWith("render."))continue;const s=n.name,a=n.value.trim();let i,l,c;if("render.plugin"===s){let e;try{e=o(a,t)}catch(e){console.error(e);continue}if(!e)continue;i=e.plugin,l=e.args}else{const e=s.slice(7);if(i=r.get(e),!i)continue;if(a.startsWith(e+"(")){let e;try{e=o(a,t)}catch(e){console.error(e);continue}if(!e)continue;i=e.plugin,l=e.args}else l=[a]}"function"==typeof i.onBeforeExecute&&i.onBeforeExecute(e,a,t);try{c=i.execute(...l)}catch(e){continue}e.textContent=null==c?"":String(c),"function"==typeof i.onAfterExecute&&i.onAfterExecute(e,a,t)}for(const n of r.values())"function"==typeof n.onAfterRender&&await n.onAfterRender(e,t)}function rendux(e=this.shadowRoot||this){const n=this;for(const t of r.values())"function"==typeof t.onBeforeRender&&t.onBeforeRender(e,n);const o=document,a=n.getAttribute("logs"),i=Boolean(a),l=a?new Set(a.split(",").map(e=>e.trim().toLowerCase())):new Set,c=e=>l.has("all")||l.has(e.toLowerCase())||l.has(("x-"+e).toLowerCase()),u=i&&l.has("plugins"),f=(...e)=>console.warn(...e);n._xRenderCache||(n._xRenderCache=new Map),n._xRenderOriginalText||(n._xRenderOriginalText=new WeakMap),n._xIfData||(n._xIfData=new WeakMap),n._cloneContext||(n._cloneContext=new WeakMap),n._xClassCache||(n._xClassCache=new Map),n._xForCache||(n._xForCache=new WeakMap),n.__mirrorContainer||(n.__mirrorContainer=o.createDocumentFragment());const p={};function d(e){let t=e;for(;t;){const e=n._cloneContext.get(t);if(e)return n.getAttribute("logs")&&n.getAttribute("logs").includes("plugins")&&console.log("Found context for element:",t,e),e;t=t.parentNode}return n.getAttribute("logs")&&n.getAttribute("logs").includes("plugins")&&console.log("Using default component context:",n),n}function h(e,r){if(!e)return!0;const n=d(r);try{return t(e,{this:n,...p})}catch(t){return void f(`[evaluate] "${e}" failed in`,n,t)}}Object.getOwnPropertyNames(Object.getPrototypeOf(n)).forEach(e=>{"function"==typeof n[e]&&"constructor"!==e&&(p[e]=n[e].bind(n))}),p.plugins=r;const x=i&&c("for");x&&console.groupCollapsed("x-for");Array.from(e.querySelectorAll("template[x-for]")).concat(Array.from(n.__mirrorContainer.querySelectorAll("template[x-for]"))).forEach(e=>{let t,r,s;e._xForMeta||(e._xForMeta={parent:e.parentNode,next:e.nextSibling},n.__mirrorContainer.appendChild(e));try{({loopVar:t,indexVar:r,arrayPath:s}=function(e){const t=e.match(/^\s*(?:\(\s*([^,\s]+)\s*,\s*([^,\s]+)\s*\)|([^,\s()]+))\s+(?:in|of)\s+(.+)$/);if(!t)throw new Error("Invalid x-for: "+e);return{loopVar:t[1]||t[3],indexVar:t[2]||null,arrayPath:t[4].trim()}}(e.getAttribute("x-for")))}catch(e){return void f("[x-for]",e.message)}const a=function(e,t){const r=d(t),n=e.match(/([^[.\]]+)|\[(\d+)\]/g);if(n)return n.reduce((e,t)=>{if(null!=e){if(t.startsWith("[")){const r=parseInt(t.slice(1,-1),10);return Array.isArray(e)?e[r]:void 0}return e[t]}},r)}(s,e);if(!Array.isArray(a))return void f(`[x-for] expected array at ${s}`,a);x&&console.log(`iterating ${s} → length ${a.length}`);const i=function(e){return JSON.stringify(e)}(a),l=n._xForCache.get(e);l&&l.arrayRef===a&&l.length===a.length&&l.signature===i?x&&console.log(" → skipped (no change)"):(n._xForCache.set(e,{arrayRef:a,length:a.length,signature:i}),e._forClones&&e._forClones.forEach(e=>e.remove()),e._forClones=[],a.forEach((s,a)=>{x&&console.groupCollapsed(` index ${a}`);const i=o.createDocumentFragment();i.appendChild(e.content.cloneNode(!0));const l=(c=t,u=s,f=r,p=a,new Proxy(n,{has:(e,t)=>t===c||f&&t===f||t in e,get:(e,t)=>t===c?u:f&&t===f?p:e[t]}));var c,u,f,p,d,h;d=i,h=l,n._cloneContext.set(d,h),d.querySelectorAll("*").forEach(e=>n._cloneContext.set(e,h));const g=n._xRenderCache,y=n._xRenderOriginalText;for(n._xRenderCache=new Map,n._xRenderOriginalText=new WeakMap,rendux.call(n,i),n._xRenderCache=g,n._xRenderOriginalText=y;i.firstChild;){const t=i.firstChild;e._xForMeta.parent.insertBefore(t,e._xForMeta.next),e._forClones.push(t)}x&&console.groupEnd()}))}),x&&console.groupEnd();const g=i&&c("if");Array.from(e.querySelectorAll("[x-if]")).concat(Array.from(n.__mirrorContainer.querySelectorAll("[x-if]"))).forEach(e=>{const t=e.getAttribute("x-if")?.trim(),r=!t||h(t,e);g&&console.groupCollapsed("x-if",e,t,"→",r);let s=n._xIfData.get(e);s||(s={placeholder:o.createComment("x-if placeholder"),isHidden:!1},n._xIfData.set(e,s)),r||s.isHidden?r&&s.isHidden&&(s.placeholder.parentNode.replaceChild(e,s.placeholder),s.isHidden=!1):(e.parentNode.replaceChild(s.placeholder,e),n.__mirrorContainer.appendChild(e),s.isHidden=!0),g&&console.groupEnd()}),0===n._xRenderCache.size&&Array.from(e.querySelectorAll("[render]")).forEach(e=>{const t=e.getAttribute("render")?.trim();t&&(n._xRenderCache.set(e,t),n._xRenderOriginalText.set(e,e.textContent))}),Array.from(e.querySelectorAll("[x-class]")).forEach(e=>{const t=e.getAttribute("x-class");null==t||n._xClassCache.has(e)||n._xClassCache.set(e,t)});const y=i&&c("attr");Array.from(e.querySelectorAll("*")).forEach(e=>{Array.from(e.attributes).forEach(t=>{if(t.name.startsWith("x-")&&!["x-for","x-key","x-class","x-if","x-hidden"].includes(t.name)){const o=t.name,s=r.get(o);if(s&&"attribute"===s.target){const r=h(t.value.trim(),e);try{u&&console.log("[plugin]",`Executing ${o} with:`,{element:e,value:r,component:n}),s.execute(e,r,n)}catch(e){u&&console.error("[plugin]",`Error executing ${o}:`,e)}}else{const r=t.name.slice(2),n=h(t.value.trim(),e);y&&console.groupCollapsed("x-attr",e,r,"=",n),n?e.setAttribute(r,String(n)):e.removeAttribute(r),y&&console.groupEnd()}}})});const m=i&&c("class");m&&console.groupCollapsed("x-class");for(const[e,t]of n._xClassCache){m&&console.log("element →",e);const r=t.trim();if(r.includes("(")){const t=/\(\s*([^,]+?)\s*,\s*([^)]+?)\s*\)/g;n._xClassDynamicValues||(n._xClassDynamicValues=new Map);(n._xClassDynamicValues.get(e)||[]).forEach(t=>e.classList.remove(t));const o=new Set;let s;for(;s=t.exec(r);){const t=s[1].trim(),r=s[2].trim();let n;n=/^[\w\-\s]+$/.test(t)?t:h(t,e);const a=Boolean(h(r,e));let i=[];"string"==typeof n?i=n.split(/\s+/).filter(Boolean):Array.isArray(n)?i=n:n&&"object"==typeof n&&(i=Object.keys(n).filter(e=>n[e])),a&&i.forEach(t=>e.classList.add(t)),i.forEach(e=>o.add(e)),m&&console.log(` ${t} → [${i.join(" ")}] (= ${a})`)}n._xClassDynamicValues.set(e,Array.from(o))}else{n._xClassDynamicValues||(n._xClassDynamicValues=new Map);let t;(n._xClassDynamicValues.get(e)||[]).forEach(t=>e.classList.remove(t));let o=!0;if(!r.includes(",")&&/[?:]/.test(r))t=h(r,e);else{const n=r.indexOf(","),s=n>=0?r.slice(0,n).trim():r,a=n>=0?r.slice(n+1).trim():"true";o=Boolean(h(a,e)),t=s}const s=[];"string"==typeof t?s.push(...t.split(/\s+/).filter(Boolean)):Array.isArray(t)?s.push(...t):t&&"object"==typeof t&&s.push(...Object.keys(t).filter(e=>t[e])),s.forEach(t=>{o?e.classList.add(t):e.classList.remove(t)}),m&&console.log(` x-class ${r} →`,s,`ok=${o}`),n._xClassDynamicValues.set(e,s)}}m&&console.groupEnd();const _=i&&c("render");_&&console.groupCollapsed("render");for(const[e,t]of n._xRenderCache){const r=n._xIfData.get(e);if(r&&r.isHidden)continue;_&&console.log("element →",e,"expr=",t);const o=t.indexOf(","),s=o<0?t:t.slice(0,o).trim(),a=h(o<0?"true":t.slice(o+1).trim(),e);let i;if(a){let t=h(s,e);if(void 0===t)i=n._xRenderOriginalText.get(e)||"";else if(null!=t&&"object"==typeof t)try{i=JSON.stringify(t,null,2)}catch{i=String(t)}else i=null==t||"boolean"==typeof t?"":String(t)}else i=n._xRenderOriginalText.get(e)||"";e.textContent!==i&&(e.textContent=i),_&&console.log(` → "${i}" (cond=${a})`)}_&&console.groupEnd(),Array.from(e.querySelectorAll("*")).forEach(e=>{const t=n._xIfData.get(e);t&&t.isHidden||[["render","render"]].forEach(([t,r])=>{e.hasAttribute(t)&&!c(r)&&e.removeAttribute(t)})}),function e(r){Array.from(r.querySelectorAll("*")).forEach(e=>{Array.from(e.attributes).forEach(r=>{if(r.name.startsWith("@")){const o=r.name.slice(1),s=r.value.trim();e._xEventListeners&&e._xEventListeners[o]&&e.removeEventListener(o,e._xEventListeners[o]),e._xEventListeners||(e._xEventListeners={});const a=d(e),i=new Proxy(a,{get:(e,t)=>t in e?e[t]:n[t]}),l=function(e){try{return t(s,{this:i,event:e,...p})}catch(e){f(`[rendux @${o}] Error evaluating: ${s}`,e)}};e.addEventListener(o,l),e._xEventListeners[o]=l}})}),Array.from(r.querySelectorAll("slot")).forEach(t=>{(t.assignedElements?t.assignedElements({flatten:!0}):[]).forEach(t=>{e(t)})})}(e),s(e,n)}rendux.use=function(e){return n(e),rendux},"undefined"!=typeof module&&module.exports&&(module.exports={rendux:rendux,use:n,process:s,plugins:r,parsePluginCall:o}),exports.parsePluginCall=o,exports.plugins=r,exports.process=s,exports.rendux=rendux,exports.use=n;
|
|
1
|
+
/*! rendux v0.93.3 | Copyright (c) JULY 2025 Yannick J.A. CHARLERY | This software is licensed for non-commercial use only. Commercial licensing available upon request. For license details: https://github.com/ynck-chrl/rendux */
|
|
2
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e={Math:Math,Date:Date,Number:Number,String:String,Boolean:Boolean,JSON:JSON,parseInt:parseInt,parseFloat:parseFloat,isFinite:isFinite,Array:Array};function t(t,r={}){const n=function(e){const t=[];let r=0;for(;r<e.length;){let n=e[r];if(/\s/.test(n)){r++;continue}if('"'===n||"'"===n){const o=n;let s="";for(r++;r<e.length&&e[r]!==o;)"\\"===e[r]?(r++,r<e.length&&(s+=e[r++])):s+=e[r++];r++,t.push({type:"string",value:s});continue}if(/[0-9]/.test(n)||"."===n&&/[0-9]/.test(e[r+1])){let n=r;for(;r<e.length&&/[0-9]/.test(e[r]);)r++;if("."===e[r])for(r++;r<e.length&&/[0-9]/.test(e[r]);)r++;const o=parseFloat(e.slice(n,r));t.push({type:"number",value:o});continue}if(/[a-zA-Z_$]/.test(n)){let n=r;for(r++;r<e.length&&/[a-zA-Z0-9_$]/.test(e[r]);)r++;const o=e.slice(n,r);"true"===o||"false"===o?t.push({type:"boolean",value:"true"===o}):"null"===o?t.push({type:"null",value:null}):t.push({type:"identifier",value:o});continue}const o=e.substr(r,2),s=e.substr(r,3);if(["===","!=="].includes(s))t.push({type:"operator",value:s}),r+=3;else if(["==","!=",">=","<=","&&","||"].includes(o))t.push({type:"operator",value:o}),r+=2;else{if(!["+","-","*","/","%",">","<","!","?",":","(",")","[","]",".",","].includes(n))throw new Error(`Invalid character '${n}' in expression`);t.push({type:"operator",value:n}),r++}}return t.push({type:"EOF"}),t}(t);let o=0;function s(){return n[o]||{type:"EOF"}}function l(){return n[o++]||{type:"EOF"}}function a(e,t){const r=s();if(r.type!==e||void 0!==t&&r.value!==t)throw new Error(`Expected ${t||e} but got ${r.value}`);return l(),r}function i(e){const t=s();return"operator"===t.type&&t.value===e}const c=u();if("EOF"!==s().type)throw new Error(`Unexpected token: ${s().value}`);return c;function u(){let e=function(){let e=f();for(;i("||");){l();const t=f();e=e||t}return e}();if(i("?")){l();const t=u();a("operator",":");const r=u();e=e?t:r}return e}function f(){let e=d();for(;i("&&");){l();const t=d();e=e&&t}return e}function d(){let e=h();for(;["==","!=","===","!=="].includes(s().value);){const t=l().value,r=h();switch(t){case"==":e=e==r;break;case"!=":e=e!=r;break;case"===":e=e===r;break;case"!==":e=e!==r}}return e}function h(){let e=p();for(;[">","<",">=","<="].includes(s().value);){const t=l().value,r=p();switch(t){case">":e=e>r;break;case"<":e=e<r;break;case">=":e=e>=r;break;case"<=":e=e<=r}}return e}function p(){let e=x();for(;["+","-"].includes(s().value);){const t=l().value,r=x();e="+"===t?e+r:e-r}return e}function x(){let e=g();for(;["*","/","%"].includes(s().value);){const t=l().value,r=g();switch(t){case"*":e*=r;break;case"/":e/=r;break;case"%":e%=r}}return e}function g(){if(["!","+","-"].includes(s().value)){const e=l().value,t=g();switch(e){case"!":return!t;case"+":return+t;case"-":return-t}}return function(){const t=s();if("number"===t.type||"string"===t.type||"boolean"===t.type||"null"===t.type)return l(),t.value;if("identifier"===t.type){l();let n=function(t){if(t in r)return r[t];if(t in e)return e[t];if(null!=r.this&&t in r.this)return r.this[t];throw new Error(`Unknown identifier: ${t}`)}(t.value);for(;;)if(i(".")){l();const e=a("identifier").value;n=null==n?void 0:n[e]}else if(i("[")){l();const e=u();a("operator","]"),n=null==n?void 0:n[e]}else{if(!i("("))break;{l();const e=[];if(!i(")"))do{e.push(u())}while(i(",")&&l());if(a("operator",")"),"function"!=typeof n)throw new Error(`'${t.value}' is not a function`);n=n.apply(r.this,e)}}return n}if(i("(")){l();const e=u();return a("operator",")"),e}throw new Error(`Unexpected token: ${t.value}`)}()}}const r=new Map;function n(e){if(!e||!e.name)throw new Error("Invalid plugin");r.set(e.name,e)}function o(e,t={}){const n=e.match(/^([a-zA-Z_$][\w$]*)\s*\(\s*(.*)\s*\)$/);if(!n)return null;const o=n[1],s=r.get(o);if(!s)return null;const l=n[2].trim();if(""===l)return{plugin:s,args:[]};return{plugin:s,args:l.split(/\s*,\s*/).map(e=>{if(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);if(/^-?\d+(?:\.\d+)?$/.test(e))return parseFloat(e);if(e in t)return t[e];throw new Error(`Unknown identifier: ${e}`)})}}async function s(e=document,t={}){const n=Array.from(e.querySelectorAll("*")).filter(e=>Array.from(e.attributes).some(e=>e.name.startsWith("render.")));for(const e of n)for(const n of Array.from(e.attributes)){if(!n.name.startsWith("render."))continue;const s=n.name,l=n.value.trim();let a,i,c;if("render.plugin"===s){let e;try{e=o(l,t)}catch(e){console.error(e);continue}if(!e)continue;a=e.plugin,i=e.args}else{const e=s.slice(7);if(a=r.get(e),!a)continue;if(l.startsWith(e+"(")){let e;try{e=o(l,t)}catch(e){console.error(e);continue}if(!e)continue;a=e.plugin,i=e.args}else i=[l]}"function"==typeof a.onBeforeExecute&&a.onBeforeExecute(e,l,t);try{c=a.execute(...i)}catch(e){continue}e.textContent=null==c?"":String(c),"function"==typeof a.onAfterExecute&&a.onAfterExecute(e,l,t)}for(const n of r.values())"function"==typeof n.onAfterRender&&await n.onAfterRender(e,t)}function rendux(e,n){const o=e,l=n;let a=n.shadowRoot||n;if(!a)throw new Error("rendux requires a DOM element as the second argument");for(const e of r.values())"function"==typeof e.onBeforeRender&&e.onBeforeRender(a,o);const i=document,c=l.getAttribute&&l.getAttribute("logs"),u=Boolean(c),f=c?new Set(c.split(",").map(e=>e.trim().toLowerCase())):new Set,d=e=>f.has("all")||f.has(e.toLowerCase())||f.has(("x-"+e).toLowerCase()),h=u&&f.has("plugins"),p=(...e)=>console.warn(...e);l._xRenderCache||(l._xRenderCache=new Map),l._xRenderOriginalText||(l._xRenderOriginalText=new WeakMap),l._xIfData||(l._xIfData=new WeakMap),l._cloneContext||(l._cloneContext=new WeakMap),l._xClassCache||(l._xClassCache=new Map),l._xForCache||(l._xForCache=new WeakMap),l.__mirrorContainer||(l.__mirrorContainer=i.createDocumentFragment());const x={};function g(e){let t=e;for(;t;){const e=l._cloneContext.get(t);if(e)return l.getAttribute&&l.getAttribute("logs")&&l.getAttribute("logs").includes("plugins")&&console.log("Found context for element:",t,e),e;t=t.parentNode}return l.getAttribute&&l.getAttribute("logs")&&l.getAttribute("logs").includes("plugins")&&console.log("Using default component context:",o),o}function y(e,r){if(!e)return!0;const n=g(r);try{return t(e,{this:n,...x})}catch(t){return void p(`[evaluate] "${e}" failed in`,n,t)}}function m(e,t){const r=g(t),n=e.match(/([^[.\]]+)|\[(\d+)\]/g);if(n)return n.reduce((e,t)=>{if(null!=e){if(t.startsWith("[")){const r=parseInt(t.slice(1,-1),10);return Array.isArray(e)?e[r]:void 0}return e[t]}},r)}function A(e){const t=e.match(/^\s*(?:\(\s*([^,\s]+)\s*,\s*([^,\s]+)\s*\)|([^,\s()]+))\s+(?:in|of)\s+(.+)$/);if(!t)throw new Error("Invalid x-for: "+e);return{loopVar:t[1]||t[3],indexVar:t[2]||null,arrayPath:t[4].trim()}}function C(e,t,r,n,o){return new Proxy(e,{has:(e,r)=>r===t||n&&r===n||r in e,get:(e,s)=>s===t?r:n&&s===n?o:e[s]})}function _(e,t){l._cloneContext.set(e,t),e.querySelectorAll("*").forEach(e=>l._cloneContext.set(e,t))}l&&Object.getPrototypeOf(l)&&Object.getOwnPropertyNames(Object.getPrototypeOf(l)).forEach(e=>{"function"==typeof l[e]&&"constructor"!==e&&(x[e]=l[e].bind(l))}),x.plugins=r;const E=u&&d("for");function b(e){try{const t=new WeakSet;return JSON.stringify(e,(e,r)=>{if("function"!=typeof r&&!e.startsWith("$")){if("object"==typeof r&&null!==r){if(t.has(r))return"[Circular]";t.add(r)}return r}})}catch(t){return`${e.length}-${e[0]?.name||""}-${e[e.length-1]?.name||""}`}}E&&console.groupCollapsed("x-for");let v=new Set,w=!0;for(;w;){const e=Array.from(a.querySelectorAll("template[x-for]")).concat(Array.from(l.__mirrorContainer.querySelectorAll("template[x-for]"))).filter(e=>!v.has(e));if(0===e.length){w=!1;break}e.forEach(e=>{let r,n,s;v.add(e),e._xForMeta||(e._xForMeta={parent:e.parentNode,next:e.nextSibling},l.__mirrorContainer.appendChild(e));try{({loopVar:r,indexVar:n,arrayPath:s}=A(e.getAttribute("x-for")))}catch(e){return void p("[x-for]",e.message)}const a=m(s,e);if(!Array.isArray(a))return void p(`[x-for] expected array at ${s}`,a);E&&console.log(`iterating ${s} → length ${a.length}`);const c=e.content.cloneNode(!0).querySelector("*"),u=c&&c.hasAttribute("x-key");if(!u){const t=b(a),r=l._xForCache.get(e);if(r&&r.arrayRef===a&&r.length===a.length&&r.signature===t)return void(E&&console.log(" → skipped (no change)"));l._xForCache.set(e,{arrayRef:a,length:a.length,signature:t})}if(u&&e._forClones&&e._forClones.length>0){E&&console.log(" → using x-key diffing");const s=c.getAttribute("x-key"),u=new Map;e._forClones.forEach(e=>{if(1===e.nodeType){const t=e.getAttribute("x-key");t&&u.set(t,e)}});const f=[],d=new Set;a.forEach((a,c)=>{E&&console.groupCollapsed(` index ${c}`);const h=C(o,r,a,n,c);let g;try{g=t(s,{this:h,...x})}catch(e){p("[x-for] Error evaluating x-key:",e),g=c}const y=String(g);if(u.has(y)){const e=u.get(y);d.add(e),E&&console.log(` → reusing node for key: ${y}`),l._cloneContext.set(e,h),f.push(e)}else{E&&console.log(` → creating new node for key: ${y}`);const t=i.createDocumentFragment();t.appendChild(e.content.cloneNode(!0));const r=t.firstElementChild;if(r){t.removeChild(r),r.setAttribute("x-key",y),_(r,h);(r.hasAttribute("render")?[r,...r.querySelectorAll("[render]")]:r.querySelectorAll("[render]")).forEach(e=>{const t=e.getAttribute("render")?.trim();t&&(l._xRenderCache.set(e,t),l._xRenderOriginalText.set(e,e.textContent))});(r.hasAttribute("x-class")?[r,...r.querySelectorAll("[x-class]")]:r.querySelectorAll("[x-class]")).forEach(e=>{const t=e.getAttribute("x-class");null!=t&&l._xClassCache.set(e,t)}),f.push(r)}}E&&console.groupEnd()}),e._forClones.forEach(e=>{if(!d.has(e)){if(E&&console.log(" → removing unused node"),1===e.nodeType){(e.hasAttribute("render")?[e,...e.querySelectorAll("[render]")]:e.querySelectorAll("[render]")).forEach(e=>{l._xRenderCache.delete(e),l._xRenderOriginalText.delete(e)});(e.hasAttribute("x-class")?[e,...e.querySelectorAll("[x-class]")]:e.querySelectorAll("[x-class]")).forEach(e=>{l._xClassCache.delete(e),l._xClassDynamicValues.delete(e)})}e.remove()}}),f.forEach((t,r)=>{const n=e._xForMeta.parent,o=r<f.length-1?f[r+1]:e._xForMeta.next;t.parentNode&&t.nextSibling===o||n.insertBefore(t,o)}),e._forClones=f}else E&&u&&console.log(" → first render with x-key"),E&&!u&&console.log(" → no x-key, full re-render"),e._forClones&&e._forClones.forEach(e=>{if(1===e.nodeType){(e.hasAttribute("render")?[e,...e.querySelectorAll("[render]")]:e.querySelectorAll("[render]")).forEach(e=>{l._xRenderCache.delete(e),l._xRenderOriginalText.delete(e)});(e.hasAttribute("x-class")?[e,...e.querySelectorAll("[x-class]")]:e.querySelectorAll("[x-class]")).forEach(e=>{l._xClassCache.delete(e),l._xClassDynamicValues.delete(e)})}e.remove()}),e._forClones=[],a.forEach((s,a)=>{E&&console.groupCollapsed(` index ${a}`);const c=i.createDocumentFragment();c.appendChild(e.content.cloneNode(!0));const f=C(o,r,s,n,a);if(_(c,f),u){const e=c.firstElementChild;if(e){const r=e.getAttribute("x-key");if(r)try{const n=t(r,{this:f,...x});e.setAttribute("x-key",String(n))}catch(t){e.setAttribute("x-key",String(a))}}}for(;c.firstChild;){const t=c.firstChild;if(e._xForMeta.parent.insertBefore(t,e._xForMeta.next),e._forClones.push(t),1===t.nodeType){(t.hasAttribute("render")?[t,...t.querySelectorAll("[render]")]:t.querySelectorAll("[render]")).forEach(e=>{const t=e.getAttribute("render")?.trim();t&&(l._xRenderCache.set(e,t),l._xRenderOriginalText.set(e,e.textContent))});(t.hasAttribute("x-class")?[t,...t.querySelectorAll("[x-class]")]:t.querySelectorAll("[x-class]")).forEach(e=>{const t=e.getAttribute("x-class");null!=t&&l._xClassCache.set(e,t)})}}E&&console.groupEnd()})})}E&&console.groupEnd();const S=u&&d("if");Array.from(a.querySelectorAll("[x-if]")).concat(Array.from(l.__mirrorContainer.querySelectorAll("[x-if]"))).forEach(e=>{const t=e.getAttribute("x-if")?.trim(),r=!t||y(t,e);S&&console.groupCollapsed("x-if",e,t,"→",r);let n=l._xIfData.get(e);n||(n={placeholder:i.createComment("x-if placeholder"),isHidden:!1},l._xIfData.set(e,n)),r||n.isHidden?r&&n.isHidden&&(n.placeholder.parentNode.replaceChild(e,n.placeholder),n.isHidden=!1):(e.parentNode.replaceChild(n.placeholder,e),l.__mirrorContainer.appendChild(e),n.isHidden=!0),S&&console.groupEnd()}),Array.from(a.querySelectorAll("[render]")).forEach(e=>{if(!l._xRenderCache.has(e)){const t=e.getAttribute("render")?.trim();t&&(l._xRenderCache.set(e,t),l._xRenderOriginalText.set(e,e.textContent))}}),Array.from(a.querySelectorAll("[x-class]")).forEach(e=>{const t=e.getAttribute("x-class");null==t||l._xClassCache.has(e)||l._xClassCache.set(e,t)});const $=u&&d("attr");Array.from(a.querySelectorAll("*")).forEach(e=>{Array.from(e.attributes).forEach(t=>{if(t.name.startsWith("x-")&&!["x-for","x-key","x-class","x-if","x-hidden"].includes(t.name)){const n=t.name,s=r.get(n);if(s&&"attribute"===s.target){const r=y(t.value.trim(),e);try{h&&console.log("[plugin]",`Executing ${n} with:`,{element:e,value:r,component:o}),s.execute(e,r,o)}catch(e){h&&console.error("[plugin]",`Error executing ${n}:`,e)}}else{const r=t.name.slice(2),n=y(t.value.trim(),e);$&&console.groupCollapsed("x-attr",e,r,"=",n),n?e.setAttribute(r,String(n)):e.removeAttribute(r),$&&console.groupEnd()}}})});const k=u&&d("class");k&&console.groupCollapsed("x-class");for(const[e,t]of l._xClassCache){k&&console.log("element →",e);const r=t.trim();if(r.includes("(")){const t=/\(\s*([^,]+?)\s*,\s*([^)]+?)\s*\)/g;l._xClassDynamicValues||(l._xClassDynamicValues=new Map);(l._xClassDynamicValues.get(e)||[]).forEach(t=>e.classList.remove(t));const n=new Set;let o;for(;o=t.exec(r);){const t=o[1].trim(),r=o[2].trim();let s;s=/^[\w\-\s]+$/.test(t)?t:y(t,e);const l=Boolean(y(r,e));let a=[];"string"==typeof s?a=s.split(/\s+/).filter(Boolean):Array.isArray(s)?a=s:s&&"object"==typeof s&&(a=Object.keys(s).filter(e=>s[e])),l&&a.forEach(t=>e.classList.add(t)),a.forEach(e=>n.add(e)),k&&console.log(` ${t} → [${a.join(" ")}] (= ${l})`)}l._xClassDynamicValues.set(e,Array.from(n))}else{l._xClassDynamicValues||(l._xClassDynamicValues=new Map);let t;(l._xClassDynamicValues.get(e)||[]).forEach(t=>e.classList.remove(t));let n=!0;if(!r.includes(",")&&/[?:]/.test(r))t=y(r,e);else{const o=r.indexOf(","),s=o>=0?r.slice(0,o).trim():r,l=o>=0?r.slice(o+1).trim():"true";n=Boolean(y(l,e)),t=s}const o=[];"string"==typeof t?o.push(...t.split(/\s+/).filter(Boolean)):Array.isArray(t)?o.push(...t):t&&"object"==typeof t&&o.push(...Object.keys(t).filter(e=>t[e])),o.forEach(t=>{n?e.classList.add(t):e.classList.remove(t)}),k&&console.log(` x-class ${r} →`,o,`ok=${n}`),l._xClassDynamicValues.set(e,o)}}k&&console.groupEnd();const q=u&&d("render");q&&console.groupCollapsed("render");for(const[e,t]of l._xRenderCache){const r=l._xIfData.get(e);if(r&&r.isHidden)continue;q&&console.log("element →",e,"expr=",t);const n=t.indexOf(","),o=n<0?t:t.slice(0,n).trim(),s=y(n<0?"true":t.slice(n+1).trim(),e);let a;if(s){let t=y(o,e);if(void 0===t)a=l._xRenderOriginalText.get(e)||"";else if(null!=t&&"object"==typeof t)try{a=JSON.stringify(t,null,2)}catch{a=String(t)}else a=null==t||"boolean"==typeof t?"":String(t)}else a=l._xRenderOriginalText.get(e)||"";e.textContent!==a&&(e.textContent=a),q&&console.log(` → "${a}" (cond=${s})`)}q&&console.groupEnd(),Array.from(a.querySelectorAll("*")).forEach(e=>{const t=l._xIfData.get(e);t&&t.isHidden||[["render","render"]].forEach(([t,r])=>{e.hasAttribute(t)&&!d(r)&&e.removeAttribute(t)})}),function e(r){Array.from(r.querySelectorAll("*")).forEach(e=>{Array.from(e.attributes).forEach(r=>{if(r.name.startsWith("@")){const n=r.name.slice(1),s=r.value.trim();e._xEventListeners&&e._xEventListeners[n]&&e.removeEventListener(n,e._xEventListeners[n]),e._xEventListeners||(e._xEventListeners={});const l=g(e),a=new Proxy(l,{get:(e,t)=>t in e?e[t]:o[t]}),i=function(e){try{return t(s,{this:a,event:e,...x})}catch(e){p(`[rendux @${n}] Error evaluating: ${s}`,e)}};e.addEventListener(n,i),e._xEventListeners[n]=i}})}),Array.from(r.querySelectorAll("slot")).forEach(t=>{(t.assignedElements?t.assignedElements({flatten:!0}):[]).forEach(t=>{e(t)})})}(a),s(a,o)}rendux.use=function(e){return n(e),rendux},"undefined"!=typeof module&&module.exports&&(module.exports={rendux:rendux,use:n,process:s,plugins:r,parsePluginCall:o}),exports.parsePluginCall=o,exports.plugins=r,exports.process=s,exports.rendux=rendux,exports.use=n;
|
package/dist/rendux.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! rendux v0.
|
|
2
|
-
const e={Math:Math,Date:Date,Number:Number,String:String,Boolean:Boolean,JSON:JSON,parseInt:parseInt,parseFloat:parseFloat,isFinite:isFinite,Array:Array};function t(t,r={}){const n=function(e){const t=[];let r=0;for(;r<e.length;){let n=e[r];if(/\s/.test(n)){r++;continue}if('"'===n||"'"===n){const o=n;let s="";for(r++;r<e.length&&e[r]!==o;)"\\"===e[r]?(r++,r<e.length&&(s+=e[r++])):s+=e[r++];r++,t.push({type:"string",value:s});continue}if(/[0-9]/.test(n)||"."===n&&/[0-9]/.test(e[r+1])){let n=r;for(;r<e.length&&/[0-9]/.test(e[r]);)r++;if("."===e[r])for(r++;r<e.length&&/[0-9]/.test(e[r]);)r++;const o=parseFloat(e.slice(n,r));t.push({type:"number",value:o});continue}if(/[a-zA-Z_$]/.test(n)){let n=r;for(r++;r<e.length&&/[a-zA-Z0-9_$]/.test(e[r]);)r++;const o=e.slice(n,r);"true"===o||"false"===o?t.push({type:"boolean",value:"true"===o}):"null"===o?t.push({type:"null",value:null}):t.push({type:"identifier",value:o});continue}const o=e.substr(r,2),s=e.substr(r,3);if(["===","!=="].includes(s))t.push({type:"operator",value:s}),r+=3;else if(["==","!=",">=","<=","&&","||"].includes(o))t.push({type:"operator",value:o}),r+=2;else{if(!["+","-","*","/","%",">","<","!","?",":","(",")","[","]",".",","].includes(n))throw new Error(`Invalid character '${n}' in expression`);t.push({type:"operator",value:n}),r++}}return t.push({type:"EOF"}),t}(t);let o=0;function s(){return n[o]||{type:"EOF"}}function a(){return n[o++]||{type:"EOF"}}function i(e,t){const r=s();if(r.type!==e||void 0!==t&&r.value!==t)throw new Error(`Expected ${t||e} but got ${r.value}`);return a(),r}function l(e){const t=s();return"operator"===t.type&&t.value===e}const c=u();if("EOF"!==s().type)throw new Error(`Unexpected token: ${s().value}`);return c;function u(){let e=function(){let e=f();for(;l("||");){a();const t=f();e=e||t}return e}();if(l("?")){a();const t=u();i("operator",":");const r=u();e=e?t:r}return e}function f(){let e=p();for(;l("&&");){a();const t=p();e=e&&t}return e}function p(){let e=d();for(;["==","!=","===","!=="].includes(s().value);){const t=a().value,r=d();switch(t){case"==":e=e==r;break;case"!=":e=e!=r;break;case"===":e=e===r;break;case"!==":e=e!==r}}return e}function d(){let e=h();for(;[">","<",">=","<="].includes(s().value);){const t=a().value,r=h();switch(t){case">":e=e>r;break;case"<":e=e<r;break;case">=":e=e>=r;break;case"<=":e=e<=r}}return e}function h(){let e=x();for(;["+","-"].includes(s().value);){const t=a().value,r=x();e="+"===t?e+r:e-r}return e}function x(){let e=g();for(;["*","/","%"].includes(s().value);){const t=a().value,r=g();switch(t){case"*":e*=r;break;case"/":e/=r;break;case"%":e%=r}}return e}function g(){if(["!","+","-"].includes(s().value)){const e=a().value,t=g();switch(e){case"!":return!t;case"+":return+t;case"-":return-t}}return function(){const t=s();if("number"===t.type||"string"===t.type||"boolean"===t.type||"null"===t.type)return a(),t.value;if("identifier"===t.type){a();let n=function(t){if(t in r)return r[t];if(t in e)return e[t];if(null!=r.this&&t in r.this)return r.this[t];throw new Error(`Unknown identifier: ${t}`)}(t.value);for(;;)if(l(".")){a();const e=i("identifier").value;n=null==n?void 0:n[e]}else if(l("[")){a();const e=u();i("operator","]"),n=null==n?void 0:n[e]}else{if(!l("("))break;{a();const e=[];if(!l(")"))do{e.push(u())}while(l(",")&&a());if(i("operator",")"),"function"!=typeof n)throw new Error(`'${t.value}' is not a function`);n=n.apply(r.this,e)}}return n}if(l("(")){a();const e=u();return i("operator",")"),e}throw new Error(`Unexpected token: ${t.value}`)}()}}const r=new Map;function n(e){if(!e||!e.name)throw new Error("Invalid plugin");r.set(e.name,e)}function o(e,t={}){const n=e.match(/^([a-zA-Z_$][\w$]*)\s*\(\s*(.*)\s*\)$/);if(!n)return null;const o=n[1],s=r.get(o);if(!s)return null;const a=n[2].trim();if(""===a)return{plugin:s,args:[]};return{plugin:s,args:a.split(/\s*,\s*/).map(e=>{if(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);if(/^-?\d+(?:\.\d+)?$/.test(e))return parseFloat(e);if(e in t)return t[e];throw new Error(`Unknown identifier: ${e}`)})}}async function s(e=document,t={}){const n=Array.from(e.querySelectorAll("*")).filter(e=>Array.from(e.attributes).some(e=>e.name.startsWith("render.")));for(const e of n)for(const n of Array.from(e.attributes)){if(!n.name.startsWith("render."))continue;const s=n.name,a=n.value.trim();let i,l,c;if("render.plugin"===s){let e;try{e=o(a,t)}catch(e){console.error(e);continue}if(!e)continue;i=e.plugin,l=e.args}else{const e=s.slice(7);if(i=r.get(e),!i)continue;if(a.startsWith(e+"(")){let e;try{e=o(a,t)}catch(e){console.error(e);continue}if(!e)continue;i=e.plugin,l=e.args}else l=[a]}"function"==typeof i.onBeforeExecute&&i.onBeforeExecute(e,a,t);try{c=i.execute(...l)}catch(e){continue}e.textContent=null==c?"":String(c),"function"==typeof i.onAfterExecute&&i.onAfterExecute(e,a,t)}for(const n of r.values())"function"==typeof n.onAfterRender&&await n.onAfterRender(e,t)}function rendux(e=this.shadowRoot||this){const n=this;for(const t of r.values())"function"==typeof t.onBeforeRender&&t.onBeforeRender(e,n);const o=document,a=n.getAttribute("logs"),i=Boolean(a),l=a?new Set(a.split(",").map(e=>e.trim().toLowerCase())):new Set,c=e=>l.has("all")||l.has(e.toLowerCase())||l.has(("x-"+e).toLowerCase()),u=i&&l.has("plugins"),f=(...e)=>console.warn(...e);n._xRenderCache||(n._xRenderCache=new Map),n._xRenderOriginalText||(n._xRenderOriginalText=new WeakMap),n._xIfData||(n._xIfData=new WeakMap),n._cloneContext||(n._cloneContext=new WeakMap),n._xClassCache||(n._xClassCache=new Map),n._xForCache||(n._xForCache=new WeakMap),n.__mirrorContainer||(n.__mirrorContainer=o.createDocumentFragment());const p={};function d(e){let t=e;for(;t;){const e=n._cloneContext.get(t);if(e)return n.getAttribute("logs")&&n.getAttribute("logs").includes("plugins")&&console.log("Found context for element:",t,e),e;t=t.parentNode}return n.getAttribute("logs")&&n.getAttribute("logs").includes("plugins")&&console.log("Using default component context:",n),n}function h(e,r){if(!e)return!0;const n=d(r);try{return t(e,{this:n,...p})}catch(t){return void f(`[evaluate] "${e}" failed in`,n,t)}}Object.getOwnPropertyNames(Object.getPrototypeOf(n)).forEach(e=>{"function"==typeof n[e]&&"constructor"!==e&&(p[e]=n[e].bind(n))}),p.plugins=r;const x=i&&c("for");x&&console.groupCollapsed("x-for");Array.from(e.querySelectorAll("template[x-for]")).concat(Array.from(n.__mirrorContainer.querySelectorAll("template[x-for]"))).forEach(e=>{let t,r,s;e._xForMeta||(e._xForMeta={parent:e.parentNode,next:e.nextSibling},n.__mirrorContainer.appendChild(e));try{({loopVar:t,indexVar:r,arrayPath:s}=function(e){const t=e.match(/^\s*(?:\(\s*([^,\s]+)\s*,\s*([^,\s]+)\s*\)|([^,\s()]+))\s+(?:in|of)\s+(.+)$/);if(!t)throw new Error("Invalid x-for: "+e);return{loopVar:t[1]||t[3],indexVar:t[2]||null,arrayPath:t[4].trim()}}(e.getAttribute("x-for")))}catch(e){return void f("[x-for]",e.message)}const a=function(e,t){const r=d(t),n=e.match(/([^[.\]]+)|\[(\d+)\]/g);if(n)return n.reduce((e,t)=>{if(null!=e){if(t.startsWith("[")){const r=parseInt(t.slice(1,-1),10);return Array.isArray(e)?e[r]:void 0}return e[t]}},r)}(s,e);if(!Array.isArray(a))return void f(`[x-for] expected array at ${s}`,a);x&&console.log(`iterating ${s} → length ${a.length}`);const i=function(e){return JSON.stringify(e)}(a),l=n._xForCache.get(e);l&&l.arrayRef===a&&l.length===a.length&&l.signature===i?x&&console.log(" → skipped (no change)"):(n._xForCache.set(e,{arrayRef:a,length:a.length,signature:i}),e._forClones&&e._forClones.forEach(e=>e.remove()),e._forClones=[],a.forEach((s,a)=>{x&&console.groupCollapsed(` index ${a}`);const i=o.createDocumentFragment();i.appendChild(e.content.cloneNode(!0));const l=(c=t,u=s,f=r,p=a,new Proxy(n,{has:(e,t)=>t===c||f&&t===f||t in e,get:(e,t)=>t===c?u:f&&t===f?p:e[t]}));var c,u,f,p,d,h;d=i,h=l,n._cloneContext.set(d,h),d.querySelectorAll("*").forEach(e=>n._cloneContext.set(e,h));const g=n._xRenderCache,y=n._xRenderOriginalText;for(n._xRenderCache=new Map,n._xRenderOriginalText=new WeakMap,rendux.call(n,i),n._xRenderCache=g,n._xRenderOriginalText=y;i.firstChild;){const t=i.firstChild;e._xForMeta.parent.insertBefore(t,e._xForMeta.next),e._forClones.push(t)}x&&console.groupEnd()}))}),x&&console.groupEnd();const g=i&&c("if");Array.from(e.querySelectorAll("[x-if]")).concat(Array.from(n.__mirrorContainer.querySelectorAll("[x-if]"))).forEach(e=>{const t=e.getAttribute("x-if")?.trim(),r=!t||h(t,e);g&&console.groupCollapsed("x-if",e,t,"→",r);let s=n._xIfData.get(e);s||(s={placeholder:o.createComment("x-if placeholder"),isHidden:!1},n._xIfData.set(e,s)),r||s.isHidden?r&&s.isHidden&&(s.placeholder.parentNode.replaceChild(e,s.placeholder),s.isHidden=!1):(e.parentNode.replaceChild(s.placeholder,e),n.__mirrorContainer.appendChild(e),s.isHidden=!0),g&&console.groupEnd()}),0===n._xRenderCache.size&&Array.from(e.querySelectorAll("[render]")).forEach(e=>{const t=e.getAttribute("render")?.trim();t&&(n._xRenderCache.set(e,t),n._xRenderOriginalText.set(e,e.textContent))}),Array.from(e.querySelectorAll("[x-class]")).forEach(e=>{const t=e.getAttribute("x-class");null==t||n._xClassCache.has(e)||n._xClassCache.set(e,t)});const y=i&&c("attr");Array.from(e.querySelectorAll("*")).forEach(e=>{Array.from(e.attributes).forEach(t=>{if(t.name.startsWith("x-")&&!["x-for","x-key","x-class","x-if","x-hidden"].includes(t.name)){const o=t.name,s=r.get(o);if(s&&"attribute"===s.target){const r=h(t.value.trim(),e);try{u&&console.log("[plugin]",`Executing ${o} with:`,{element:e,value:r,component:n}),s.execute(e,r,n)}catch(e){u&&console.error("[plugin]",`Error executing ${o}:`,e)}}else{const r=t.name.slice(2),n=h(t.value.trim(),e);y&&console.groupCollapsed("x-attr",e,r,"=",n),n?e.setAttribute(r,String(n)):e.removeAttribute(r),y&&console.groupEnd()}}})});const m=i&&c("class");m&&console.groupCollapsed("x-class");for(const[e,t]of n._xClassCache){m&&console.log("element →",e);const r=t.trim();if(r.includes("(")){const t=/\(\s*([^,]+?)\s*,\s*([^)]+?)\s*\)/g;n._xClassDynamicValues||(n._xClassDynamicValues=new Map);(n._xClassDynamicValues.get(e)||[]).forEach(t=>e.classList.remove(t));const o=new Set;let s;for(;s=t.exec(r);){const t=s[1].trim(),r=s[2].trim();let n;n=/^[\w\-\s]+$/.test(t)?t:h(t,e);const a=Boolean(h(r,e));let i=[];"string"==typeof n?i=n.split(/\s+/).filter(Boolean):Array.isArray(n)?i=n:n&&"object"==typeof n&&(i=Object.keys(n).filter(e=>n[e])),a&&i.forEach(t=>e.classList.add(t)),i.forEach(e=>o.add(e)),m&&console.log(` ${t} → [${i.join(" ")}] (= ${a})`)}n._xClassDynamicValues.set(e,Array.from(o))}else{n._xClassDynamicValues||(n._xClassDynamicValues=new Map);let t;(n._xClassDynamicValues.get(e)||[]).forEach(t=>e.classList.remove(t));let o=!0;if(!r.includes(",")&&/[?:]/.test(r))t=h(r,e);else{const n=r.indexOf(","),s=n>=0?r.slice(0,n).trim():r,a=n>=0?r.slice(n+1).trim():"true";o=Boolean(h(a,e)),t=s}const s=[];"string"==typeof t?s.push(...t.split(/\s+/).filter(Boolean)):Array.isArray(t)?s.push(...t):t&&"object"==typeof t&&s.push(...Object.keys(t).filter(e=>t[e])),s.forEach(t=>{o?e.classList.add(t):e.classList.remove(t)}),m&&console.log(` x-class ${r} →`,s,`ok=${o}`),n._xClassDynamicValues.set(e,s)}}m&&console.groupEnd();const _=i&&c("render");_&&console.groupCollapsed("render");for(const[e,t]of n._xRenderCache){const r=n._xIfData.get(e);if(r&&r.isHidden)continue;_&&console.log("element →",e,"expr=",t);const o=t.indexOf(","),s=o<0?t:t.slice(0,o).trim(),a=h(o<0?"true":t.slice(o+1).trim(),e);let i;if(a){let t=h(s,e);if(void 0===t)i=n._xRenderOriginalText.get(e)||"";else if(null!=t&&"object"==typeof t)try{i=JSON.stringify(t,null,2)}catch{i=String(t)}else i=null==t||"boolean"==typeof t?"":String(t)}else i=n._xRenderOriginalText.get(e)||"";e.textContent!==i&&(e.textContent=i),_&&console.log(` → "${i}" (cond=${a})`)}_&&console.groupEnd(),Array.from(e.querySelectorAll("*")).forEach(e=>{const t=n._xIfData.get(e);t&&t.isHidden||[["render","render"]].forEach(([t,r])=>{e.hasAttribute(t)&&!c(r)&&e.removeAttribute(t)})}),function e(r){Array.from(r.querySelectorAll("*")).forEach(e=>{Array.from(e.attributes).forEach(r=>{if(r.name.startsWith("@")){const o=r.name.slice(1),s=r.value.trim();e._xEventListeners&&e._xEventListeners[o]&&e.removeEventListener(o,e._xEventListeners[o]),e._xEventListeners||(e._xEventListeners={});const a=d(e),i=new Proxy(a,{get:(e,t)=>t in e?e[t]:n[t]}),l=function(e){try{return t(s,{this:i,event:e,...p})}catch(e){f(`[rendux @${o}] Error evaluating: ${s}`,e)}};e.addEventListener(o,l),e._xEventListeners[o]=l}})}),Array.from(r.querySelectorAll("slot")).forEach(t=>{(t.assignedElements?t.assignedElements({flatten:!0}):[]).forEach(t=>{e(t)})})}(e),s(e,n)}rendux.use=function(e){return n(e),rendux},"undefined"!=typeof module&&module.exports&&(module.exports={rendux:rendux,use:n,process:s,plugins:r,parsePluginCall:o});export{o as parsePluginCall,r as plugins,s as process,rendux,n as use};
|
|
1
|
+
/*! rendux v0.93.3 | Copyright (c) JULY 2025 Yannick J.A. CHARLERY | This software is licensed for non-commercial use only. Commercial licensing available upon request. For license details: https://github.com/ynck-chrl/rendux */
|
|
2
|
+
const e={Math:Math,Date:Date,Number:Number,String:String,Boolean:Boolean,JSON:JSON,parseInt:parseInt,parseFloat:parseFloat,isFinite:isFinite,Array:Array};function t(t,r={}){const n=function(e){const t=[];let r=0;for(;r<e.length;){let n=e[r];if(/\s/.test(n)){r++;continue}if('"'===n||"'"===n){const o=n;let s="";for(r++;r<e.length&&e[r]!==o;)"\\"===e[r]?(r++,r<e.length&&(s+=e[r++])):s+=e[r++];r++,t.push({type:"string",value:s});continue}if(/[0-9]/.test(n)||"."===n&&/[0-9]/.test(e[r+1])){let n=r;for(;r<e.length&&/[0-9]/.test(e[r]);)r++;if("."===e[r])for(r++;r<e.length&&/[0-9]/.test(e[r]);)r++;const o=parseFloat(e.slice(n,r));t.push({type:"number",value:o});continue}if(/[a-zA-Z_$]/.test(n)){let n=r;for(r++;r<e.length&&/[a-zA-Z0-9_$]/.test(e[r]);)r++;const o=e.slice(n,r);"true"===o||"false"===o?t.push({type:"boolean",value:"true"===o}):"null"===o?t.push({type:"null",value:null}):t.push({type:"identifier",value:o});continue}const o=e.substr(r,2),s=e.substr(r,3);if(["===","!=="].includes(s))t.push({type:"operator",value:s}),r+=3;else if(["==","!=",">=","<=","&&","||"].includes(o))t.push({type:"operator",value:o}),r+=2;else{if(!["+","-","*","/","%",">","<","!","?",":","(",")","[","]",".",","].includes(n))throw new Error(`Invalid character '${n}' in expression`);t.push({type:"operator",value:n}),r++}}return t.push({type:"EOF"}),t}(t);let o=0;function s(){return n[o]||{type:"EOF"}}function l(){return n[o++]||{type:"EOF"}}function a(e,t){const r=s();if(r.type!==e||void 0!==t&&r.value!==t)throw new Error(`Expected ${t||e} but got ${r.value}`);return l(),r}function i(e){const t=s();return"operator"===t.type&&t.value===e}const c=u();if("EOF"!==s().type)throw new Error(`Unexpected token: ${s().value}`);return c;function u(){let e=function(){let e=f();for(;i("||");){l();const t=f();e=e||t}return e}();if(i("?")){l();const t=u();a("operator",":");const r=u();e=e?t:r}return e}function f(){let e=d();for(;i("&&");){l();const t=d();e=e&&t}return e}function d(){let e=h();for(;["==","!=","===","!=="].includes(s().value);){const t=l().value,r=h();switch(t){case"==":e=e==r;break;case"!=":e=e!=r;break;case"===":e=e===r;break;case"!==":e=e!==r}}return e}function h(){let e=p();for(;[">","<",">=","<="].includes(s().value);){const t=l().value,r=p();switch(t){case">":e=e>r;break;case"<":e=e<r;break;case">=":e=e>=r;break;case"<=":e=e<=r}}return e}function p(){let e=x();for(;["+","-"].includes(s().value);){const t=l().value,r=x();e="+"===t?e+r:e-r}return e}function x(){let e=g();for(;["*","/","%"].includes(s().value);){const t=l().value,r=g();switch(t){case"*":e*=r;break;case"/":e/=r;break;case"%":e%=r}}return e}function g(){if(["!","+","-"].includes(s().value)){const e=l().value,t=g();switch(e){case"!":return!t;case"+":return+t;case"-":return-t}}return function(){const t=s();if("number"===t.type||"string"===t.type||"boolean"===t.type||"null"===t.type)return l(),t.value;if("identifier"===t.type){l();let n=function(t){if(t in r)return r[t];if(t in e)return e[t];if(null!=r.this&&t in r.this)return r.this[t];throw new Error(`Unknown identifier: ${t}`)}(t.value);for(;;)if(i(".")){l();const e=a("identifier").value;n=null==n?void 0:n[e]}else if(i("[")){l();const e=u();a("operator","]"),n=null==n?void 0:n[e]}else{if(!i("("))break;{l();const e=[];if(!i(")"))do{e.push(u())}while(i(",")&&l());if(a("operator",")"),"function"!=typeof n)throw new Error(`'${t.value}' is not a function`);n=n.apply(r.this,e)}}return n}if(i("(")){l();const e=u();return a("operator",")"),e}throw new Error(`Unexpected token: ${t.value}`)}()}}const r=new Map;function n(e){if(!e||!e.name)throw new Error("Invalid plugin");r.set(e.name,e)}function o(e,t={}){const n=e.match(/^([a-zA-Z_$][\w$]*)\s*\(\s*(.*)\s*\)$/);if(!n)return null;const o=n[1],s=r.get(o);if(!s)return null;const l=n[2].trim();if(""===l)return{plugin:s,args:[]};return{plugin:s,args:l.split(/\s*,\s*/).map(e=>{if(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);if(/^-?\d+(?:\.\d+)?$/.test(e))return parseFloat(e);if(e in t)return t[e];throw new Error(`Unknown identifier: ${e}`)})}}async function s(e=document,t={}){const n=Array.from(e.querySelectorAll("*")).filter(e=>Array.from(e.attributes).some(e=>e.name.startsWith("render.")));for(const e of n)for(const n of Array.from(e.attributes)){if(!n.name.startsWith("render."))continue;const s=n.name,l=n.value.trim();let a,i,c;if("render.plugin"===s){let e;try{e=o(l,t)}catch(e){console.error(e);continue}if(!e)continue;a=e.plugin,i=e.args}else{const e=s.slice(7);if(a=r.get(e),!a)continue;if(l.startsWith(e+"(")){let e;try{e=o(l,t)}catch(e){console.error(e);continue}if(!e)continue;a=e.plugin,i=e.args}else i=[l]}"function"==typeof a.onBeforeExecute&&a.onBeforeExecute(e,l,t);try{c=a.execute(...i)}catch(e){continue}e.textContent=null==c?"":String(c),"function"==typeof a.onAfterExecute&&a.onAfterExecute(e,l,t)}for(const n of r.values())"function"==typeof n.onAfterRender&&await n.onAfterRender(e,t)}function rendux(e,n){const o=e,l=n;let a=n.shadowRoot||n;if(!a)throw new Error("rendux requires a DOM element as the second argument");for(const e of r.values())"function"==typeof e.onBeforeRender&&e.onBeforeRender(a,o);const i=document,c=l.getAttribute&&l.getAttribute("logs"),u=Boolean(c),f=c?new Set(c.split(",").map(e=>e.trim().toLowerCase())):new Set,d=e=>f.has("all")||f.has(e.toLowerCase())||f.has(("x-"+e).toLowerCase()),h=u&&f.has("plugins"),p=(...e)=>console.warn(...e);l._xRenderCache||(l._xRenderCache=new Map),l._xRenderOriginalText||(l._xRenderOriginalText=new WeakMap),l._xIfData||(l._xIfData=new WeakMap),l._cloneContext||(l._cloneContext=new WeakMap),l._xClassCache||(l._xClassCache=new Map),l._xForCache||(l._xForCache=new WeakMap),l.__mirrorContainer||(l.__mirrorContainer=i.createDocumentFragment());const x={};function g(e){let t=e;for(;t;){const e=l._cloneContext.get(t);if(e)return l.getAttribute&&l.getAttribute("logs")&&l.getAttribute("logs").includes("plugins")&&console.log("Found context for element:",t,e),e;t=t.parentNode}return l.getAttribute&&l.getAttribute("logs")&&l.getAttribute("logs").includes("plugins")&&console.log("Using default component context:",o),o}function y(e,r){if(!e)return!0;const n=g(r);try{return t(e,{this:n,...x})}catch(t){return void p(`[evaluate] "${e}" failed in`,n,t)}}function m(e,t){const r=g(t),n=e.match(/([^[.\]]+)|\[(\d+)\]/g);if(n)return n.reduce((e,t)=>{if(null!=e){if(t.startsWith("[")){const r=parseInt(t.slice(1,-1),10);return Array.isArray(e)?e[r]:void 0}return e[t]}},r)}function A(e){const t=e.match(/^\s*(?:\(\s*([^,\s]+)\s*,\s*([^,\s]+)\s*\)|([^,\s()]+))\s+(?:in|of)\s+(.+)$/);if(!t)throw new Error("Invalid x-for: "+e);return{loopVar:t[1]||t[3],indexVar:t[2]||null,arrayPath:t[4].trim()}}function C(e,t,r,n,o){return new Proxy(e,{has:(e,r)=>r===t||n&&r===n||r in e,get:(e,s)=>s===t?r:n&&s===n?o:e[s]})}function _(e,t){l._cloneContext.set(e,t),e.querySelectorAll("*").forEach(e=>l._cloneContext.set(e,t))}l&&Object.getPrototypeOf(l)&&Object.getOwnPropertyNames(Object.getPrototypeOf(l)).forEach(e=>{"function"==typeof l[e]&&"constructor"!==e&&(x[e]=l[e].bind(l))}),x.plugins=r;const E=u&&d("for");function b(e){try{const t=new WeakSet;return JSON.stringify(e,(e,r)=>{if("function"!=typeof r&&!e.startsWith("$")){if("object"==typeof r&&null!==r){if(t.has(r))return"[Circular]";t.add(r)}return r}})}catch(t){return`${e.length}-${e[0]?.name||""}-${e[e.length-1]?.name||""}`}}E&&console.groupCollapsed("x-for");let v=new Set,w=!0;for(;w;){const e=Array.from(a.querySelectorAll("template[x-for]")).concat(Array.from(l.__mirrorContainer.querySelectorAll("template[x-for]"))).filter(e=>!v.has(e));if(0===e.length){w=!1;break}e.forEach(e=>{let r,n,s;v.add(e),e._xForMeta||(e._xForMeta={parent:e.parentNode,next:e.nextSibling},l.__mirrorContainer.appendChild(e));try{({loopVar:r,indexVar:n,arrayPath:s}=A(e.getAttribute("x-for")))}catch(e){return void p("[x-for]",e.message)}const a=m(s,e);if(!Array.isArray(a))return void p(`[x-for] expected array at ${s}`,a);E&&console.log(`iterating ${s} → length ${a.length}`);const c=e.content.cloneNode(!0).querySelector("*"),u=c&&c.hasAttribute("x-key");if(!u){const t=b(a),r=l._xForCache.get(e);if(r&&r.arrayRef===a&&r.length===a.length&&r.signature===t)return void(E&&console.log(" → skipped (no change)"));l._xForCache.set(e,{arrayRef:a,length:a.length,signature:t})}if(u&&e._forClones&&e._forClones.length>0){E&&console.log(" → using x-key diffing");const s=c.getAttribute("x-key"),u=new Map;e._forClones.forEach(e=>{if(1===e.nodeType){const t=e.getAttribute("x-key");t&&u.set(t,e)}});const f=[],d=new Set;a.forEach((a,c)=>{E&&console.groupCollapsed(` index ${c}`);const h=C(o,r,a,n,c);let g;try{g=t(s,{this:h,...x})}catch(e){p("[x-for] Error evaluating x-key:",e),g=c}const y=String(g);if(u.has(y)){const e=u.get(y);d.add(e),E&&console.log(` → reusing node for key: ${y}`),l._cloneContext.set(e,h),f.push(e)}else{E&&console.log(` → creating new node for key: ${y}`);const t=i.createDocumentFragment();t.appendChild(e.content.cloneNode(!0));const r=t.firstElementChild;if(r){t.removeChild(r),r.setAttribute("x-key",y),_(r,h);(r.hasAttribute("render")?[r,...r.querySelectorAll("[render]")]:r.querySelectorAll("[render]")).forEach(e=>{const t=e.getAttribute("render")?.trim();t&&(l._xRenderCache.set(e,t),l._xRenderOriginalText.set(e,e.textContent))});(r.hasAttribute("x-class")?[r,...r.querySelectorAll("[x-class]")]:r.querySelectorAll("[x-class]")).forEach(e=>{const t=e.getAttribute("x-class");null!=t&&l._xClassCache.set(e,t)}),f.push(r)}}E&&console.groupEnd()}),e._forClones.forEach(e=>{if(!d.has(e)){if(E&&console.log(" → removing unused node"),1===e.nodeType){(e.hasAttribute("render")?[e,...e.querySelectorAll("[render]")]:e.querySelectorAll("[render]")).forEach(e=>{l._xRenderCache.delete(e),l._xRenderOriginalText.delete(e)});(e.hasAttribute("x-class")?[e,...e.querySelectorAll("[x-class]")]:e.querySelectorAll("[x-class]")).forEach(e=>{l._xClassCache.delete(e),l._xClassDynamicValues.delete(e)})}e.remove()}}),f.forEach((t,r)=>{const n=e._xForMeta.parent,o=r<f.length-1?f[r+1]:e._xForMeta.next;t.parentNode&&t.nextSibling===o||n.insertBefore(t,o)}),e._forClones=f}else E&&u&&console.log(" → first render with x-key"),E&&!u&&console.log(" → no x-key, full re-render"),e._forClones&&e._forClones.forEach(e=>{if(1===e.nodeType){(e.hasAttribute("render")?[e,...e.querySelectorAll("[render]")]:e.querySelectorAll("[render]")).forEach(e=>{l._xRenderCache.delete(e),l._xRenderOriginalText.delete(e)});(e.hasAttribute("x-class")?[e,...e.querySelectorAll("[x-class]")]:e.querySelectorAll("[x-class]")).forEach(e=>{l._xClassCache.delete(e),l._xClassDynamicValues.delete(e)})}e.remove()}),e._forClones=[],a.forEach((s,a)=>{E&&console.groupCollapsed(` index ${a}`);const c=i.createDocumentFragment();c.appendChild(e.content.cloneNode(!0));const f=C(o,r,s,n,a);if(_(c,f),u){const e=c.firstElementChild;if(e){const r=e.getAttribute("x-key");if(r)try{const n=t(r,{this:f,...x});e.setAttribute("x-key",String(n))}catch(t){e.setAttribute("x-key",String(a))}}}for(;c.firstChild;){const t=c.firstChild;if(e._xForMeta.parent.insertBefore(t,e._xForMeta.next),e._forClones.push(t),1===t.nodeType){(t.hasAttribute("render")?[t,...t.querySelectorAll("[render]")]:t.querySelectorAll("[render]")).forEach(e=>{const t=e.getAttribute("render")?.trim();t&&(l._xRenderCache.set(e,t),l._xRenderOriginalText.set(e,e.textContent))});(t.hasAttribute("x-class")?[t,...t.querySelectorAll("[x-class]")]:t.querySelectorAll("[x-class]")).forEach(e=>{const t=e.getAttribute("x-class");null!=t&&l._xClassCache.set(e,t)})}}E&&console.groupEnd()})})}E&&console.groupEnd();const S=u&&d("if");Array.from(a.querySelectorAll("[x-if]")).concat(Array.from(l.__mirrorContainer.querySelectorAll("[x-if]"))).forEach(e=>{const t=e.getAttribute("x-if")?.trim(),r=!t||y(t,e);S&&console.groupCollapsed("x-if",e,t,"→",r);let n=l._xIfData.get(e);n||(n={placeholder:i.createComment("x-if placeholder"),isHidden:!1},l._xIfData.set(e,n)),r||n.isHidden?r&&n.isHidden&&(n.placeholder.parentNode.replaceChild(e,n.placeholder),n.isHidden=!1):(e.parentNode.replaceChild(n.placeholder,e),l.__mirrorContainer.appendChild(e),n.isHidden=!0),S&&console.groupEnd()}),Array.from(a.querySelectorAll("[render]")).forEach(e=>{if(!l._xRenderCache.has(e)){const t=e.getAttribute("render")?.trim();t&&(l._xRenderCache.set(e,t),l._xRenderOriginalText.set(e,e.textContent))}}),Array.from(a.querySelectorAll("[x-class]")).forEach(e=>{const t=e.getAttribute("x-class");null==t||l._xClassCache.has(e)||l._xClassCache.set(e,t)});const $=u&&d("attr");Array.from(a.querySelectorAll("*")).forEach(e=>{Array.from(e.attributes).forEach(t=>{if(t.name.startsWith("x-")&&!["x-for","x-key","x-class","x-if","x-hidden"].includes(t.name)){const n=t.name,s=r.get(n);if(s&&"attribute"===s.target){const r=y(t.value.trim(),e);try{h&&console.log("[plugin]",`Executing ${n} with:`,{element:e,value:r,component:o}),s.execute(e,r,o)}catch(e){h&&console.error("[plugin]",`Error executing ${n}:`,e)}}else{const r=t.name.slice(2),n=y(t.value.trim(),e);$&&console.groupCollapsed("x-attr",e,r,"=",n),n?e.setAttribute(r,String(n)):e.removeAttribute(r),$&&console.groupEnd()}}})});const k=u&&d("class");k&&console.groupCollapsed("x-class");for(const[e,t]of l._xClassCache){k&&console.log("element →",e);const r=t.trim();if(r.includes("(")){const t=/\(\s*([^,]+?)\s*,\s*([^)]+?)\s*\)/g;l._xClassDynamicValues||(l._xClassDynamicValues=new Map);(l._xClassDynamicValues.get(e)||[]).forEach(t=>e.classList.remove(t));const n=new Set;let o;for(;o=t.exec(r);){const t=o[1].trim(),r=o[2].trim();let s;s=/^[\w\-\s]+$/.test(t)?t:y(t,e);const l=Boolean(y(r,e));let a=[];"string"==typeof s?a=s.split(/\s+/).filter(Boolean):Array.isArray(s)?a=s:s&&"object"==typeof s&&(a=Object.keys(s).filter(e=>s[e])),l&&a.forEach(t=>e.classList.add(t)),a.forEach(e=>n.add(e)),k&&console.log(` ${t} → [${a.join(" ")}] (= ${l})`)}l._xClassDynamicValues.set(e,Array.from(n))}else{l._xClassDynamicValues||(l._xClassDynamicValues=new Map);let t;(l._xClassDynamicValues.get(e)||[]).forEach(t=>e.classList.remove(t));let n=!0;if(!r.includes(",")&&/[?:]/.test(r))t=y(r,e);else{const o=r.indexOf(","),s=o>=0?r.slice(0,o).trim():r,l=o>=0?r.slice(o+1).trim():"true";n=Boolean(y(l,e)),t=s}const o=[];"string"==typeof t?o.push(...t.split(/\s+/).filter(Boolean)):Array.isArray(t)?o.push(...t):t&&"object"==typeof t&&o.push(...Object.keys(t).filter(e=>t[e])),o.forEach(t=>{n?e.classList.add(t):e.classList.remove(t)}),k&&console.log(` x-class ${r} →`,o,`ok=${n}`),l._xClassDynamicValues.set(e,o)}}k&&console.groupEnd();const q=u&&d("render");q&&console.groupCollapsed("render");for(const[e,t]of l._xRenderCache){const r=l._xIfData.get(e);if(r&&r.isHidden)continue;q&&console.log("element →",e,"expr=",t);const n=t.indexOf(","),o=n<0?t:t.slice(0,n).trim(),s=y(n<0?"true":t.slice(n+1).trim(),e);let a;if(s){let t=y(o,e);if(void 0===t)a=l._xRenderOriginalText.get(e)||"";else if(null!=t&&"object"==typeof t)try{a=JSON.stringify(t,null,2)}catch{a=String(t)}else a=null==t||"boolean"==typeof t?"":String(t)}else a=l._xRenderOriginalText.get(e)||"";e.textContent!==a&&(e.textContent=a),q&&console.log(` → "${a}" (cond=${s})`)}q&&console.groupEnd(),Array.from(a.querySelectorAll("*")).forEach(e=>{const t=l._xIfData.get(e);t&&t.isHidden||[["render","render"]].forEach(([t,r])=>{e.hasAttribute(t)&&!d(r)&&e.removeAttribute(t)})}),function e(r){Array.from(r.querySelectorAll("*")).forEach(e=>{Array.from(e.attributes).forEach(r=>{if(r.name.startsWith("@")){const n=r.name.slice(1),s=r.value.trim();e._xEventListeners&&e._xEventListeners[n]&&e.removeEventListener(n,e._xEventListeners[n]),e._xEventListeners||(e._xEventListeners={});const l=g(e),a=new Proxy(l,{get:(e,t)=>t in e?e[t]:o[t]}),i=function(e){try{return t(s,{this:a,event:e,...x})}catch(e){p(`[rendux @${n}] Error evaluating: ${s}`,e)}};e.addEventListener(n,i),e._xEventListeners[n]=i}})}),Array.from(r.querySelectorAll("slot")).forEach(t=>{(t.assignedElements?t.assignedElements({flatten:!0}):[]).forEach(t=>{e(t)})})}(a),s(a,o)}rendux.use=function(e){return n(e),rendux},"undefined"!=typeof module&&module.exports&&(module.exports={rendux:rendux,use:n,process:s,plugins:r,parsePluginCall:o});export{o as parsePluginCall,r as plugins,s as process,rendux,n as use};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ynck/rendux",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.93.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/rendux.cjs.min.js",
|
|
6
6
|
"module": "./dist/rendux.min.js",
|
|
@@ -8,14 +8,6 @@
|
|
|
8
8
|
".": {
|
|
9
9
|
"import": "./dist/rendux.min.js",
|
|
10
10
|
"require": "./dist/rendux.cjs.min.js"
|
|
11
|
-
},
|
|
12
|
-
"./plugin/x-tooltip": {
|
|
13
|
-
"import": "./dist/plugin/x-tooltip.min.js",
|
|
14
|
-
"require": "./dist/plugin/x-tooltip.cjs.min.js"
|
|
15
|
-
},
|
|
16
|
-
"./plugin/i18n": {
|
|
17
|
-
"import": "./dist/plugin/i18n.min.js",
|
|
18
|
-
"require": "./dist/plugin/i18n.cjs.min.js"
|
|
19
11
|
}
|
|
20
12
|
},
|
|
21
13
|
"author": "Yannick J.A. CHARLERY",
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! plugin/i18n v0.92.1 | Copyright (c) JULY 2025 Yannick J.A. CHARLERY | This software is licensed for non-commercial use only. Commercial licensing available upon request. For license details: https://github.com/ynck-chrl/rendux */
|
|
2
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e={en:{message:"Welcome to rendux!",button:"Click me",title:"Hello World"},fr:{message:"Bienvenue dans rendux!",button:"Cliquez-moi",title:"Bonjour le Monde"}};const t=function(t={}){const n=t.translations||e;let o=t.defaultLanguage||"en";return{name:"i18n",target:"render",execute:function(e,...t){const r=e.split(".");let s=n[o];for(const t of r){if(!s||"object"!=typeof s||!(t in s))return`[${e}]`;s=s[t]}if("string"==typeof s&&t.length>0){return s.replace(/\{(\d+)\}/g,(e,n)=>{const o=parseInt(n,10);return void 0!==t[o]?t[o]:e})}return s||`[${e}]`},setLanguage:e=>!!n[e]&&(o=e,!0),getLanguage:()=>o,addTranslations(e,t){n[e]||(n[e]={}),Object.assign(n[e],t)}}};exports.i18nPlugin=t;
|
package/dist/plugin/i18n.min.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! plugin/i18n v0.92.1 | Copyright (c) JULY 2025 Yannick J.A. CHARLERY | This software is licensed for non-commercial use only. Commercial licensing available upon request. For license details: https://github.com/ynck-chrl/rendux */
|
|
2
|
-
const e={en:{message:"Welcome to rendux!",button:"Click me",title:"Hello World"},fr:{message:"Bienvenue dans rendux!",button:"Cliquez-moi",title:"Bonjour le Monde"}};const t=function(t={}){const n=t.translations||e;let o=t.defaultLanguage||"en";return{name:"i18n",target:"render",execute:function(e,...t){const r=e.split(".");let s=n[o];for(const t of r){if(!s||"object"!=typeof s||!(t in s))return`[${e}]`;s=s[t]}if("string"==typeof s&&t.length>0){return s.replace(/\{(\d+)\}/g,(e,n)=>{const o=parseInt(n,10);return void 0!==t[o]?t[o]:e})}return s||`[${e}]`},setLanguage:e=>!!n[e]&&(o=e,!0),getLanguage:()=>o,addTranslations(e,t){n[e]||(n[e]={}),Object.assign(n[e],t)}}};export{t as i18nPlugin};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! plugin/x-logger v0.92.1 | Copyright (c) JULY 2025 Yannick J.A. CHARLERY | This software is licensed for non-commercial use only. Commercial licensing available upon request. For license details: https://github.com/ynck-chrl/rendux */
|
|
2
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e={name:"logger",target:"render",execute:function(e,...r){switch(e){case"logMessage":return`[Message: ${r.join(", ")}]`;case"logError":return`[Error: ${r.join(", ")}]`;case"logWarning":return`[Warning: ${r.join(", ")}]`;case"logInfo":return`[Info: ${r.join(", ")}]`;case"logDebug":return`[Debug: ${r.join(", ")}]`;case"logTable":return r.length>0&&(Array.isArray(r[0])||"object"==typeof r[0])?`[Table: ${Array.isArray(r[0])?r[0].length+" items":"object"}]`:`[Table: ${r.join(", ")}]`;default:return`[${e}: ${r.join(", ")}]`}}},r=e;exports.logger=e,exports.loggerPlugin=r;
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! plugin/x-logger v0.92.1 | Copyright (c) JULY 2025 Yannick J.A. CHARLERY | This software is licensed for non-commercial use only. Commercial licensing available upon request. For license details: https://github.com/ynck-chrl/rendux */
|
|
2
|
-
const e={name:"logger",target:"render",execute:function(e,...r){switch(e){case"logMessage":return`[Message: ${r.join(", ")}]`;case"logError":return`[Error: ${r.join(", ")}]`;case"logWarning":return`[Warning: ${r.join(", ")}]`;case"logInfo":return`[Info: ${r.join(", ")}]`;case"logDebug":return`[Debug: ${r.join(", ")}]`;case"logTable":return r.length>0&&(Array.isArray(r[0])||"object"==typeof r[0])?`[Table: ${Array.isArray(r[0])?r[0].length+" items":"object"}]`:`[Table: ${r.join(", ")}]`;default:return`[${e}: ${r.join(", ")}]`}}},r=e;export{e as logger,r as loggerPlugin};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! plugin/x-tooltip v0.92.1 | Copyright (c) JULY 2025 Yannick J.A. CHARLERY | This software is licensed for non-commercial use only. Commercial licensing available upon request. For license details: https://github.com/ynck-chrl/rendux */
|
|
2
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e={name:"x-tooltip",target:"attribute",execute:function(e,t,o){e._xTooltipElement&&e._xTooltipElement.remove();const n=document.createElement("div");n.textContent=t,n.style.cssText="\n position: absolute;\n background: #333;\n color: white;\n padding: 8px 12px;\n border-radius: 4px;\n font-size: 12px;\n white-space: nowrap;\n z-index: 1000;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.2s;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n ",document.body.appendChild(n),e._xTooltipElement=n;const i=function(t){const o=e.getBoundingClientRect(),i=window.pageXOffset||document.documentElement.scrollLeft,s=window.pageYOffset||document.documentElement.scrollTop,l=i+o.left+(o.width-n.offsetWidth)/2,p=s+o.top-n.offsetHeight-8;n.style.left=`${l}px`,n.style.top=`${p}px`,n.style.opacity="1"},s=function(){n.style.opacity="0"};if(e._xTooltipListeners&&(e.removeEventListener("mouseenter",e._xTooltipListeners.show),e.removeEventListener("mouseleave",e._xTooltipListeners.hide)),e.addEventListener("mouseenter",i),e.addEventListener("mouseleave",s),e._xTooltipListeners={show:i,hide:s},!e._xTooltipCleanup){e._xTooltipCleanup=!0;const t=new MutationObserver(o=>{o.forEach(o=>{o.removedNodes.forEach(o=>{(o===e||o.contains&&o.contains(e))&&(e._xTooltipElement&&e._xTooltipElement.remove(),t.disconnect())})})});t.observe(document.body,{childList:!0,subtree:!0})}}};exports.xTooltip=e;
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! plugin/x-tooltip v0.92.1 | Copyright (c) JULY 2025 Yannick J.A. CHARLERY | This software is licensed for non-commercial use only. Commercial licensing available upon request. For license details: https://github.com/ynck-chrl/rendux */
|
|
2
|
-
const e={name:"x-tooltip",target:"attribute",execute:function(e,t,o){e._xTooltipElement&&e._xTooltipElement.remove();const n=document.createElement("div");n.textContent=t,n.style.cssText="\n position: absolute;\n background: #333;\n color: white;\n padding: 8px 12px;\n border-radius: 4px;\n font-size: 12px;\n white-space: nowrap;\n z-index: 1000;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.2s;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n ",document.body.appendChild(n),e._xTooltipElement=n;const i=function(t){const o=e.getBoundingClientRect(),i=window.pageXOffset||document.documentElement.scrollLeft,s=window.pageYOffset||document.documentElement.scrollTop,l=i+o.left+(o.width-n.offsetWidth)/2,p=s+o.top-n.offsetHeight-8;n.style.left=`${l}px`,n.style.top=`${p}px`,n.style.opacity="1"},s=function(){n.style.opacity="0"};if(e._xTooltipListeners&&(e.removeEventListener("mouseenter",e._xTooltipListeners.show),e.removeEventListener("mouseleave",e._xTooltipListeners.hide)),e.addEventListener("mouseenter",i),e.addEventListener("mouseleave",s),e._xTooltipListeners={show:i,hide:s},!e._xTooltipCleanup){e._xTooltipCleanup=!0;const t=new MutationObserver(o=>{o.forEach(o=>{o.removedNodes.forEach(o=>{(o===e||o.contains&&o.contains(e))&&(e._xTooltipElement&&e._xTooltipElement.remove(),t.disconnect())})})});t.observe(document.body,{childList:!0,subtree:!0})}}};export{e as xTooltip};
|